@exodus/assets-feature 7.3.0 → 7.4.1
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 +12 -0
- package/client/asset-client-interface.js +19 -13
- package/module/assets-module.js +25 -11
- package/package.json +6 -5
- package/plugin/index.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
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
|
+
## [7.4.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@7.4.0...@exodus/assets-feature@7.4.1) (2025-05-15)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- fix: stop assets-feature monitor on stop (#12460)
|
|
11
|
+
|
|
12
|
+
## [7.4.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@7.3.0...@exodus/assets-feature@7.4.0) (2025-04-17)
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
- feat: validate tokens using asset-schema-validation (#12011)
|
|
17
|
+
|
|
6
18
|
## [7.3.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/assets-feature@7.2.2...@exodus/assets-feature@7.3.0) (2025-04-16)
|
|
7
19
|
|
|
8
20
|
### Features
|
|
@@ -118,6 +118,11 @@ class AssetClientInterface {
|
|
|
118
118
|
accountState,
|
|
119
119
|
batch = this.#blockchainMetadata.batch(),
|
|
120
120
|
}) => {
|
|
121
|
+
const asset = this.#assetsModule.getAsset(assetName)
|
|
122
|
+
if (!asset.baseAsset.api.features.accountState) {
|
|
123
|
+
return batch
|
|
124
|
+
}
|
|
125
|
+
|
|
121
126
|
// merge mem to keep the previous accountMem behavior
|
|
122
127
|
if (!isEmpty(newData?.mem) && (!accountState || accountState.mem)) {
|
|
123
128
|
newData = { ...newData, mem: { ...accountState?.mem, ...newData.mem } }
|
|
@@ -166,12 +171,8 @@ class AssetClientInterface {
|
|
|
166
171
|
assert(asset, `assetName ${assetName} is not supported`)
|
|
167
172
|
assert(walletAccountInstance, `walletAccountInstance ${walletAccount} is not available`)
|
|
168
173
|
|
|
169
|
-
const
|
|
170
|
-
const out = {
|
|
171
|
-
confirmationsNumber: baseAsset.api?.getConfirmationsNumber
|
|
172
|
-
? baseAsset.api.getConfirmationsNumber()
|
|
173
|
-
: 1,
|
|
174
|
-
}
|
|
174
|
+
const confirmationsNumber = await this.getConfirmationsNumber({ assetName })
|
|
175
|
+
const out = { confirmationsNumber }
|
|
175
176
|
|
|
176
177
|
const gapLimit =
|
|
177
178
|
this.#config?.compatibilityModeGapLimits?.[walletAccountInstance.compatibilityMode]
|
|
@@ -223,12 +224,17 @@ class AssetClientInterface {
|
|
|
223
224
|
addressIndex = 0,
|
|
224
225
|
chainIndex = 0,
|
|
225
226
|
}) => {
|
|
227
|
+
const [walletAccountInstance, defaultPurpose] = await Promise.all([
|
|
228
|
+
this.#getWalletAccount(walletAccount),
|
|
229
|
+
purpose === undefined
|
|
230
|
+
? this.#assetSources.getDefaultPurpose({ assetName, walletAccount })
|
|
231
|
+
: undefined,
|
|
232
|
+
])
|
|
226
233
|
if (purpose === undefined) {
|
|
227
|
-
|
|
234
|
+
purpose = defaultPurpose
|
|
228
235
|
}
|
|
229
236
|
|
|
230
237
|
const asset = this.#assetsModule.getAsset(assetName)
|
|
231
|
-
const walletAccountInstance = await this.#getWalletAccount(walletAccount)
|
|
232
238
|
const keyIdentifier = asset.baseAsset.api.getKeyIdentifier({
|
|
233
239
|
purpose,
|
|
234
240
|
accountIndex: walletAccountInstance.index,
|
|
@@ -244,18 +250,18 @@ class AssetClientInterface {
|
|
|
244
250
|
}
|
|
245
251
|
|
|
246
252
|
getExtendedPublicKey = async ({ assetName, walletAccount, purpose }) => {
|
|
247
|
-
const
|
|
248
|
-
const [walletAccountInstance, purposes] = await Promise.all([
|
|
253
|
+
const [walletAccountInstance, defaultPurpose] = await Promise.all([
|
|
249
254
|
this.#getWalletAccount(walletAccount),
|
|
250
255
|
purpose === undefined
|
|
251
|
-
?
|
|
256
|
+
? this.#assetSources.getDefaultPurpose({ assetName, walletAccount })
|
|
252
257
|
: undefined,
|
|
253
258
|
])
|
|
254
259
|
|
|
255
260
|
if (purpose === undefined) {
|
|
256
|
-
|
|
261
|
+
purpose = defaultPurpose
|
|
257
262
|
}
|
|
258
263
|
|
|
264
|
+
const asset = this.#assetsModule.getAsset(assetName)
|
|
259
265
|
const keyIdentifier = asset.baseAsset.api.getKeyIdentifier({
|
|
260
266
|
purpose,
|
|
261
267
|
accountIndex: walletAccountInstance.index,
|
|
@@ -322,7 +328,7 @@ class AssetClientInterface {
|
|
|
322
328
|
})
|
|
323
329
|
}
|
|
324
330
|
|
|
325
|
-
saveUnusedAddressIndexes = async () => {
|
|
331
|
+
saveUnusedAddressIndexes = async ({ assetName, walletAccount, changedUnusedAddressIndexes }) => {
|
|
326
332
|
// no op!! getUnusedAddressIndexes loads from tx log, not from storage
|
|
327
333
|
}
|
|
328
334
|
|
package/module/assets-module.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from './constants.js'
|
|
18
18
|
import { getAssetFromAssetId, getFetchErrorMessage, isDisabledCustomToken } from './utils.js'
|
|
19
19
|
import createFetchival from '@exodus/fetch/create-fetchival'
|
|
20
|
+
import { validateCustomToken, isValidCustomToken } from '@exodus/asset-schema-validation'
|
|
20
21
|
|
|
21
22
|
const { get, isEmpty, once, uniq } = lodash
|
|
22
23
|
|
|
@@ -78,7 +79,7 @@ export class AssetsModule {
|
|
|
78
79
|
#customTokensServerUrl
|
|
79
80
|
#updateableProps
|
|
80
81
|
#iconsStorage
|
|
81
|
-
#
|
|
82
|
+
#shouldValidateCustomToken
|
|
82
83
|
#assetPlugins
|
|
83
84
|
#combinedAssetsList
|
|
84
85
|
#storageDataKey
|
|
@@ -100,7 +101,6 @@ export class AssetsModule {
|
|
|
100
101
|
assetPlugins,
|
|
101
102
|
assetsAtom,
|
|
102
103
|
combinedAssetsList = [],
|
|
103
|
-
validateCustomToken = () => true,
|
|
104
104
|
config = {},
|
|
105
105
|
fetch,
|
|
106
106
|
logger,
|
|
@@ -115,7 +115,7 @@ export class AssetsModule {
|
|
|
115
115
|
this.#customTokensServerUrl = config.customTokensServerUrl || CT_DEFAULT_SERVER
|
|
116
116
|
this.#updateableProps = [...CT_UPDATEABLE_PROPERTIES, 'version']
|
|
117
117
|
this.#iconsStorage = iconsStorage
|
|
118
|
-
this.#
|
|
118
|
+
this.#shouldValidateCustomToken = config.shouldValidateCustomToken ?? true
|
|
119
119
|
this.#storageDataKey = config.storageDataKey || CT_DATA_KEY
|
|
120
120
|
this.#storageTimestampKey = config.storageTimestampKey || CT_TIMESTAMP_KEY
|
|
121
121
|
this.#customTokenUpdateInterval = config.customTokenUpdateInterval || CT_UPDATE_INTERVAL
|
|
@@ -223,11 +223,17 @@ export class AssetsModule {
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
const _token = await fetchTokenAndCacheError()
|
|
226
|
-
if (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
226
|
+
if (this.#shouldValidateCustomToken) {
|
|
227
|
+
try {
|
|
228
|
+
validateCustomToken(_token)
|
|
229
|
+
} catch (e) {
|
|
230
|
+
this.#logger.warn(
|
|
231
|
+
`Token did not pass validation ${baseAssetName} ${assetId}. Error: ${e.message}`
|
|
232
|
+
)
|
|
233
|
+
const err = new Error('Token did not pass validation')
|
|
234
|
+
this.#setCache(key, { cachedError: err })
|
|
235
|
+
throw err
|
|
236
|
+
}
|
|
231
237
|
}
|
|
232
238
|
|
|
233
239
|
const token = normalizeToken(_token)
|
|
@@ -319,7 +325,7 @@ export class AssetsModule {
|
|
|
319
325
|
? await this.#fetch('tokens', { tokenNames: tokenNamesToFetch }, 'tokens')
|
|
320
326
|
: []
|
|
321
327
|
|
|
322
|
-
const validTokens = fetchedTokens.filter(this.#
|
|
328
|
+
const validTokens = fetchedTokens.filter(this.#isValidCustomToken).map(normalizeToken)
|
|
323
329
|
if (validTokens.length !== fetchedTokens.length)
|
|
324
330
|
this.#logger.warn('Invalid Custom Token schema')
|
|
325
331
|
|
|
@@ -402,7 +408,7 @@ export class AssetsModule {
|
|
|
402
408
|
{ baseAssetName: baseAssetNames, lifecycleStatus, query, excludeTags, pageNumber, pageSize },
|
|
403
409
|
'tokens'
|
|
404
410
|
)
|
|
405
|
-
const validTokens = tokens.filter(this.#
|
|
411
|
+
const validTokens = tokens.filter(this.#isValidCustomToken)
|
|
406
412
|
|
|
407
413
|
if (validTokens.length !== tokens.length) this.#logger.warn('Invalid Custom Token schema')
|
|
408
414
|
|
|
@@ -419,7 +425,7 @@ export class AssetsModule {
|
|
|
419
425
|
|
|
420
426
|
#fetchUpdates = async (assetVersions) => {
|
|
421
427
|
const updatedTokens = await this.#fetch('updates', assetVersions, 'tokens')
|
|
422
|
-
const validatedTokens = updatedTokens.filter(this.#
|
|
428
|
+
const validatedTokens = updatedTokens.filter(this.#isValidCustomToken).map(normalizeToken)
|
|
423
429
|
if (validatedTokens.length !== updatedTokens.length) {
|
|
424
430
|
this.#logger.warn('Invalid Custom Token schema')
|
|
425
431
|
}
|
|
@@ -626,6 +632,14 @@ export class AssetsModule {
|
|
|
626
632
|
return !lastUpdateDate || Date.now() - lastUpdateDate > this.#customTokenUpdateInterval
|
|
627
633
|
}
|
|
628
634
|
|
|
635
|
+
#isValidCustomToken = (token) => {
|
|
636
|
+
if (!this.#shouldValidateCustomToken) {
|
|
637
|
+
return true
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
return isValidCustomToken(token)
|
|
641
|
+
}
|
|
642
|
+
|
|
629
643
|
clear = async () =>
|
|
630
644
|
this.#storage &&
|
|
631
645
|
Promise.all([
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/assets-feature",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.1",
|
|
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",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"author": "Exodus Movement, Inc.",
|
|
9
9
|
"scripts": {
|
|
10
|
-
"test": "run -T exodus-test --jest
|
|
10
|
+
"test": "run -T exodus-test --jest",
|
|
11
11
|
"lint": "run -T eslint .",
|
|
12
12
|
"lint:fix": "yarn lint --fix"
|
|
13
13
|
},
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@exodus/asset-lib": "^5.3.0",
|
|
39
|
+
"@exodus/asset-schema-validation": "^1.0.1",
|
|
39
40
|
"@exodus/assets": "^11.3.0",
|
|
40
41
|
"@exodus/atoms": "^9.0.0",
|
|
41
42
|
"@exodus/basic-utils": "^4.0.0",
|
|
@@ -64,12 +65,12 @@
|
|
|
64
65
|
"@exodus/fusion-local": "^2.1.0",
|
|
65
66
|
"@exodus/keychain": "^7.3.0",
|
|
66
67
|
"@exodus/logger": "^1.2.3",
|
|
67
|
-
"@exodus/models": "^12.
|
|
68
|
+
"@exodus/models": "^12.12.0",
|
|
68
69
|
"@exodus/osmosis-plugin": "^1.3.3",
|
|
69
70
|
"@exodus/public-key-provider": "^4.1.1",
|
|
70
71
|
"@exodus/redux-dependency-injection": "^4.1.1",
|
|
71
72
|
"@exodus/storage-memory": "^2.2.2",
|
|
72
|
-
"@exodus/wallet-accounts": "^17.5.
|
|
73
|
+
"@exodus/wallet-accounts": "^17.5.2",
|
|
73
74
|
"@exodus/wild-emitter": "^1.0.0",
|
|
74
75
|
"bip39": "^3.1.0",
|
|
75
76
|
"events": "^3.3.0",
|
|
@@ -79,5 +80,5 @@
|
|
|
79
80
|
"publishConfig": {
|
|
80
81
|
"access": "public"
|
|
81
82
|
},
|
|
82
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "45dd4907f5d65078978854be2eb397e479730c85"
|
|
83
84
|
}
|
package/plugin/index.js
CHANGED