@exodus/balances 13.15.2 → 13.15.4
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/module/index.js +66 -29
- package/package.json +6 -6
- package/redux/index.js +1 -1
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
|
+
## [13.15.4](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/balances@13.15.3...@exodus/balances@13.15.4) (2026-04-10)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- fix(balances): use Object.values() to check balancesLoaded state (#15939)
|
|
11
|
+
|
|
12
|
+
## [13.15.3](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/balances@13.15.2...@exodus/balances@13.15.3) (2026-03-11)
|
|
13
|
+
|
|
14
|
+
### Performance
|
|
15
|
+
|
|
16
|
+
- perf(balances): optimize clone and incremental asset computation (#15480)
|
|
17
|
+
|
|
6
18
|
## [13.15.2](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/balances@13.15.1...@exodus/balances@13.15.2) (2026-03-03)
|
|
7
19
|
|
|
8
20
|
### Bug Fixes
|
package/module/index.js
CHANGED
|
@@ -1,34 +1,43 @@
|
|
|
1
1
|
import { safeString } from '@exodus/safe-string'
|
|
2
|
-
import { isNumberUnit } from '@exodus/currency'
|
|
3
2
|
import { TxSet } from '@exodus/models'
|
|
4
|
-
// eslint-disable-next-line no-restricted-imports -- TODO: Fix this the next time the file is edited.
|
|
5
|
-
import lodash from 'lodash'
|
|
6
3
|
import { difference as getChanges } from '@exodus/atoms'
|
|
7
4
|
import { difference, pick, set, mapValues } from '@exodus/basic-utils'
|
|
8
5
|
import makeConcurrent from 'make-concurrent'
|
|
9
6
|
import { processAssetBalances, validateBalances } from './balances-utils.js'
|
|
10
7
|
import defaultConfig from '../default-config.js'
|
|
11
8
|
|
|
12
|
-
const
|
|
9
|
+
const zipObject = (keys, values) => {
|
|
10
|
+
const result = Object.create(null)
|
|
11
|
+
for (const [i, key] of keys.entries()) {
|
|
12
|
+
result[key] = values[i]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return result
|
|
16
|
+
}
|
|
13
17
|
|
|
14
18
|
export const cloneBalances = (balances) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
const result = Object.create(null)
|
|
20
|
+
for (const walletAccount of Object.keys(balances)) {
|
|
21
|
+
const accountBalances = balances[walletAccount]
|
|
22
|
+
const clonedAccount = Object.create(null)
|
|
23
|
+
for (const assetName of Object.keys(accountBalances)) {
|
|
24
|
+
clonedAccount[assetName] = { ...accountBalances[assetName] }
|
|
25
|
+
}
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
for (const key in balances) {
|
|
21
|
-
cloned[key] = cloneBalances(balances[key])
|
|
27
|
+
result[walletAccount] = clonedAccount
|
|
22
28
|
}
|
|
23
29
|
|
|
24
|
-
return
|
|
30
|
+
return result
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
const zipNonNull = (keys, values) =>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
values
|
|
31
|
-
|
|
33
|
+
const zipNonNull = (keys, values) => {
|
|
34
|
+
const result = Object.create(null)
|
|
35
|
+
for (const [i, key] of keys.entries()) {
|
|
36
|
+
if (values[i] != null) result[key] = values[i]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return result
|
|
40
|
+
}
|
|
32
41
|
|
|
33
42
|
class Balances {
|
|
34
43
|
#logger
|
|
@@ -134,7 +143,8 @@ class Balances {
|
|
|
134
143
|
getChanges(this.#availableAssetNamesAtom).observe(({ previous = [], current }) => {
|
|
135
144
|
this.#availableAssetNames = current
|
|
136
145
|
const added = difference(current, previous)
|
|
137
|
-
|
|
146
|
+
const removed = difference(previous, current)
|
|
147
|
+
if (added.length > 0 || removed.length > 0) this.#onAssetsChanged({ added, removed })
|
|
138
148
|
})
|
|
139
149
|
)
|
|
140
150
|
|
|
@@ -247,7 +257,7 @@ class Balances {
|
|
|
247
257
|
)
|
|
248
258
|
|
|
249
259
|
const balances = results.map(({ value }) => value).filter(Boolean)
|
|
250
|
-
return
|
|
260
|
+
return Object.assign(Object.create(null), ...balances)
|
|
251
261
|
}
|
|
252
262
|
|
|
253
263
|
#load = async ({ walletAccount }) => {
|
|
@@ -277,21 +287,48 @@ class Balances {
|
|
|
277
287
|
}
|
|
278
288
|
}
|
|
279
289
|
|
|
280
|
-
#onAssetsChanged = async (added) => {
|
|
281
|
-
if (
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
290
|
+
#onAssetsChanged = async ({ added, removed }) => {
|
|
291
|
+
if (removed.length > 0) {
|
|
292
|
+
for (const walletAccount of this.#walletAccounts) {
|
|
293
|
+
for (const assetName of removed) {
|
|
294
|
+
delete this.#balances[walletAccount]?.[assetName]
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const newSupportedAssets = added.filter(this.#isSupportedAsset)
|
|
300
|
+
const missingAssets = newSupportedAssets.filter(
|
|
301
|
+
(name) =>
|
|
302
|
+
!this.#walletAccounts.every((walletAccount) => !!this.#balances?.[walletAccount]?.[name])
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
if (missingAssets.length === 0) {
|
|
306
|
+
if (removed.length > 0) this.#flush()
|
|
286
307
|
return
|
|
287
308
|
}
|
|
288
309
|
|
|
289
|
-
this.#logger.log('
|
|
290
|
-
|
|
310
|
+
this.#logger.log('computing balances for newly available assets', missingAssets)
|
|
311
|
+
await Promise.all(
|
|
312
|
+
this.#walletAccounts.map(async (walletAccount) => {
|
|
313
|
+
const balances = await Promise.all(
|
|
314
|
+
missingAssets.map((assetName) =>
|
|
315
|
+
this.#getBalancesForAssetSource({ assetName, walletAccount })
|
|
316
|
+
)
|
|
317
|
+
)
|
|
318
|
+
if (this.#balances[walletAccount]) {
|
|
319
|
+
Object.assign(this.#balances[walletAccount], ...balances)
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
this.#flush()
|
|
291
325
|
}
|
|
292
326
|
|
|
293
|
-
#isSupportedAsset = (assetName) =>
|
|
294
|
-
this.#availableAssetNames.includes(assetName)
|
|
327
|
+
#isSupportedAsset = (assetName) => {
|
|
328
|
+
if (!this.#availableAssetNames.includes(assetName)) return false
|
|
329
|
+
const asset = this.#getAsset(assetName)
|
|
330
|
+
return asset && !asset.isCombined
|
|
331
|
+
}
|
|
295
332
|
|
|
296
333
|
#getSupportedAssetNames = () => Object.keys(this.#getAssets()).filter(this.#isSupportedAsset)
|
|
297
334
|
|
|
@@ -406,7 +443,7 @@ class Balances {
|
|
|
406
443
|
}
|
|
407
444
|
}
|
|
408
445
|
|
|
409
|
-
if (
|
|
446
|
+
if (Object.keys(changes).length > 0) this.#flush({ changes })
|
|
410
447
|
}
|
|
411
448
|
|
|
412
449
|
#recompute = async ({ walletAccounts = this.#walletAccounts } = {}) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/balances",
|
|
3
|
-
"version": "13.15.
|
|
3
|
+
"version": "13.15.4",
|
|
4
4
|
"description": "Tracks crypto balances across enabled wallet accounts.",
|
|
5
5
|
"author": "Exodus Movement, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"@exodus/atoms": "^10.0.0",
|
|
37
37
|
"@exodus/basic-utils": "^3.7.3",
|
|
38
38
|
"@exodus/core-selectors": "^4.0.0",
|
|
39
|
-
"@exodus/currency": "^
|
|
39
|
+
"@exodus/currency": "^6.0.0",
|
|
40
40
|
"@exodus/errors": "^3.0.0",
|
|
41
|
-
"@exodus/models": "^
|
|
41
|
+
"@exodus/models": "^13.0.0",
|
|
42
42
|
"@exodus/multi-account-redux": "^2.0.1",
|
|
43
43
|
"@exodus/redux-dependency-injection": "^4.0.3",
|
|
44
44
|
"@exodus/safe-string": "^1.1.0",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"@exodus/blockchain-metadata": "^17.1.0",
|
|
61
61
|
"@exodus/ethereum-meta": "^2.0.0",
|
|
62
62
|
"@exodus/fee-data-monitors": "^5.0.5",
|
|
63
|
-
"@exodus/storage-memory": "^2.
|
|
64
|
-
"@exodus/wallet-accounts": "^20.
|
|
63
|
+
"@exodus/storage-memory": "^2.4.0",
|
|
64
|
+
"@exodus/wallet-accounts": "^20.4.1",
|
|
65
65
|
"events": "^3.3.0",
|
|
66
66
|
"redux": "^4.2.1"
|
|
67
67
|
},
|
|
@@ -69,5 +69,5 @@
|
|
|
69
69
|
"access": "public",
|
|
70
70
|
"provenance": false
|
|
71
71
|
},
|
|
72
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "641c600efc2e4216570437ab642710ee9169d713"
|
|
73
73
|
}
|
package/redux/index.js
CHANGED
|
@@ -42,7 +42,7 @@ const balancesReduxDefinition = {
|
|
|
42
42
|
eventReducers: {
|
|
43
43
|
balances: (state, payload) => {
|
|
44
44
|
const { hasBalance, ...walletAccountBalances } = state
|
|
45
|
-
const balancesLoaded = Object.
|
|
45
|
+
const balancesLoaded = Object.values(walletAccountBalances).every((value) => value.loaded)
|
|
46
46
|
|
|
47
47
|
if (balancesLoaded && payload.changes && Object.keys(payload.changes).length > 0) {
|
|
48
48
|
return mergeChanges(state, payload.changes)
|