@exodus/balances 13.9.0 → 13.10.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 +16 -0
- package/module/index.js +69 -18
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
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.10.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/balances@13.9.1...@exodus/balances@13.10.0) (2025-07-04)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- feat: provide feeData to asset.api.getBalances (#13104)
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- fix: provide feeData as undefined to getBalances when disabled (#13113)
|
|
15
|
+
|
|
16
|
+
## [13.9.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/balances@13.9.0...@exodus/balances@13.9.1) (2025-06-11)
|
|
17
|
+
|
|
18
|
+
### Performance
|
|
19
|
+
|
|
20
|
+
- perf: clone balances (#12882)
|
|
21
|
+
|
|
6
22
|
## [13.9.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/balances@13.8.2...@exodus/balances@13.9.0) (2025-06-03)
|
|
7
23
|
|
|
8
24
|
### Features
|
package/module/index.js
CHANGED
|
@@ -7,12 +7,20 @@ import makeConcurrent from 'make-concurrent'
|
|
|
7
7
|
import { processAssetBalances, validateBalances } from './balances-utils.js'
|
|
8
8
|
import defaultConfig from '../default-config.js'
|
|
9
9
|
|
|
10
|
-
const {
|
|
10
|
+
const { isEmpty, merge, zipObject } = lodash
|
|
11
11
|
|
|
12
|
-
const cloneBalances = (balances) =>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
12
|
+
export const cloneBalances = (balances) => {
|
|
13
|
+
if (isNumberUnit(balances)) {
|
|
14
|
+
return balances
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const cloned = Object.create(Object.getPrototypeOf(balances))
|
|
18
|
+
for (const key in balances) {
|
|
19
|
+
cloned[key] = cloneBalances(balances[key])
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return cloned
|
|
23
|
+
}
|
|
16
24
|
|
|
17
25
|
const zipNonNull = (keys, values) =>
|
|
18
26
|
zipObject(
|
|
@@ -34,6 +42,7 @@ class Balances {
|
|
|
34
42
|
#balancesAtom
|
|
35
43
|
#accountStatesAtom
|
|
36
44
|
#txLogsAtom
|
|
45
|
+
#feeDataAtom
|
|
37
46
|
#enabledWalletAccountsAtom
|
|
38
47
|
#loaded = false
|
|
39
48
|
#subscriptions = []
|
|
@@ -47,6 +56,7 @@ class Balances {
|
|
|
47
56
|
balancesAtom,
|
|
48
57
|
txLogsAtom,
|
|
49
58
|
accountStatesAtom,
|
|
59
|
+
feeDataAtom,
|
|
50
60
|
}) {
|
|
51
61
|
this.#logger = logger
|
|
52
62
|
this.#assetsModule = assetsModule
|
|
@@ -56,6 +66,7 @@ class Balances {
|
|
|
56
66
|
this.#balancesAtom = balancesAtom
|
|
57
67
|
this.#accountStatesAtom = accountStatesAtom
|
|
58
68
|
this.#txLogsAtom = txLogsAtom
|
|
69
|
+
this.#feeDataAtom = feeDataAtom
|
|
59
70
|
this.#enabledWalletAccountsAtom = enabledWalletAccountsAtom
|
|
60
71
|
|
|
61
72
|
const shareQueue =
|
|
@@ -79,6 +90,7 @@ class Balances {
|
|
|
79
90
|
// these share a queue
|
|
80
91
|
this.#updateAssetSource = shareQueue(this.#updateAssetSource)
|
|
81
92
|
this.#handleTxLogUpdate = shareQueue(this.#handleTxLogUpdate)
|
|
93
|
+
this.#handleFeeDataUpdate = shareQueue(this.#handleFeeDataUpdate)
|
|
82
94
|
this.#recompute = shareQueue(this.#recompute)
|
|
83
95
|
this.#onAssetsChanged = shareQueue(this.#onAssetsChanged)
|
|
84
96
|
this.#getBalancesForAssetSource = swallowErrors(this.#getBalancesForAssetSource)
|
|
@@ -103,6 +115,16 @@ class Balances {
|
|
|
103
115
|
this.#handleTxLogUpdate({ walletAccount, assetName, txLog })
|
|
104
116
|
)
|
|
105
117
|
),
|
|
118
|
+
this.#feeDataAtom.observe((changes) => {
|
|
119
|
+
Object.entries(changes).forEach(([assetName, feeData]) => {
|
|
120
|
+
const asset = this.#getAsset(assetName).baseAsset
|
|
121
|
+
if (asset.api?.features?.balancesRequireFeeData)
|
|
122
|
+
this.#walletAccounts.forEach((walletAccount) => {
|
|
123
|
+
return this.#handleFeeDataUpdate({ walletAccount, assetName, feeData })
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
}),
|
|
127
|
+
|
|
106
128
|
getChanges(this.#availableAssetNamesAtom).observe(({ previous = [], current }) => {
|
|
107
129
|
this.#availableAssetNames = current
|
|
108
130
|
const added = difference(current, previous)
|
|
@@ -135,6 +157,15 @@ class Balances {
|
|
|
135
157
|
return this.#updateAssetSource(opts)
|
|
136
158
|
}
|
|
137
159
|
|
|
160
|
+
#handleFeeDataUpdate = (opts) => {
|
|
161
|
+
if (!this.#ready) {
|
|
162
|
+
this.#logger.log('ignore update from fee-data event.', { isReady: this.#ready })
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return this.#updateAssetSource(opts)
|
|
167
|
+
}
|
|
168
|
+
|
|
138
169
|
#pushIntoSharedQueue = makeConcurrent((fn) => fn(), { concurrency: 1 })
|
|
139
170
|
|
|
140
171
|
#reset = ({ walletAccounts = this.#walletAccounts } = {}) => {
|
|
@@ -154,7 +185,12 @@ class Balances {
|
|
|
154
185
|
// It adds both old and new balances to the response.
|
|
155
186
|
// Ideally, selectors should start using the new ones (total, spendable, etc)
|
|
156
187
|
|
|
157
|
-
#getBalancesFromBlockchainMetadata = ({
|
|
188
|
+
#getBalancesFromBlockchainMetadata = ({
|
|
189
|
+
assetNames,
|
|
190
|
+
accountState,
|
|
191
|
+
feeData,
|
|
192
|
+
txLogsByAssetName,
|
|
193
|
+
}) => {
|
|
158
194
|
// in the future accountState may have all the balances and we won't need to rely on txLog
|
|
159
195
|
// for now, accountState-based balance has both the baseAsset and token balances while txLog is per asset/token
|
|
160
196
|
const getAssetBalances = (assetName) => {
|
|
@@ -163,7 +199,7 @@ class Balances {
|
|
|
163
199
|
|
|
164
200
|
const zero = asset.currency.ZERO
|
|
165
201
|
|
|
166
|
-
const apiBalances = asset.api.getBalances({ asset, accountState, txLog })
|
|
202
|
+
const apiBalances = asset.api.getBalances({ asset, accountState, txLog, feeData })
|
|
167
203
|
const balances = processAssetBalances({
|
|
168
204
|
balanceFieldsConfig: this.#balanceFieldsConfig,
|
|
169
205
|
balances: apiBalances || Object.create(null),
|
|
@@ -251,24 +287,33 @@ class Balances {
|
|
|
251
287
|
#loadBlockchainMetadataForBalance = async ({
|
|
252
288
|
assetName,
|
|
253
289
|
walletAccount,
|
|
290
|
+
feeData: providedFeeData, // it's optional, undefined when balancesRequireFeeData is disabled
|
|
254
291
|
accountState: providedAccountState = null,
|
|
255
292
|
txLogsByAssetName: providedTxLogsByAssetName = {},
|
|
256
293
|
}) => {
|
|
257
294
|
const { value: txLogsByAssetSource } = await this.#txLogsAtom.get()
|
|
258
295
|
let accountState = providedAccountState
|
|
296
|
+
|
|
297
|
+
const baseAsset = this.#getAsset(assetName).baseAsset
|
|
298
|
+
|
|
259
299
|
if (!accountState) {
|
|
260
|
-
const
|
|
261
|
-
const assetNameToUse = asset.name
|
|
300
|
+
const assetNameToUse = baseAsset.name
|
|
262
301
|
const { value } = await this.#accountStatesAtom.get()
|
|
263
302
|
const cached = value[walletAccount]?.[assetNameToUse]
|
|
264
303
|
if (cached) {
|
|
265
304
|
accountState = cached
|
|
266
305
|
} else {
|
|
267
|
-
const AccountState =
|
|
306
|
+
const AccountState = baseAsset.api?.createAccountState?.()
|
|
268
307
|
accountState = AccountState?.create()
|
|
269
308
|
}
|
|
270
309
|
}
|
|
271
310
|
|
|
311
|
+
let feeData = providedFeeData
|
|
312
|
+
if (!feeData && baseAsset.api?.features?.balancesRequireFeeData) {
|
|
313
|
+
const fees = await this.#feeDataAtom.get()
|
|
314
|
+
feeData = fees[baseAsset.name]
|
|
315
|
+
}
|
|
316
|
+
|
|
272
317
|
const assetNames = this.#getRelatedAssetNames(assetName)
|
|
273
318
|
const txLogsByAssetName = zipObject(
|
|
274
319
|
assetNames,
|
|
@@ -281,6 +326,7 @@ class Balances {
|
|
|
281
326
|
)
|
|
282
327
|
|
|
283
328
|
return {
|
|
329
|
+
feeData,
|
|
284
330
|
accountState,
|
|
285
331
|
txLogsByAssetName,
|
|
286
332
|
}
|
|
@@ -291,6 +337,7 @@ class Balances {
|
|
|
291
337
|
walletAccount,
|
|
292
338
|
accountState: providedAccountState,
|
|
293
339
|
txLog: providedTxLog,
|
|
340
|
+
feeData: providedFeeData,
|
|
294
341
|
}) => {
|
|
295
342
|
if (!this.#isSupportedAsset(assetName)) return
|
|
296
343
|
|
|
@@ -299,20 +346,23 @@ class Balances {
|
|
|
299
346
|
return
|
|
300
347
|
}
|
|
301
348
|
|
|
302
|
-
const { accountState, txLogsByAssetName } =
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
349
|
+
const { accountState, txLogsByAssetName, feeData } =
|
|
350
|
+
await this.#loadBlockchainMetadataForBalance({
|
|
351
|
+
assetName,
|
|
352
|
+
walletAccount,
|
|
353
|
+
feeData: providedFeeData,
|
|
354
|
+
accountState: providedAccountState,
|
|
355
|
+
txLogsByAssetName: {
|
|
356
|
+
[assetName]: providedTxLog,
|
|
357
|
+
},
|
|
358
|
+
})
|
|
310
359
|
|
|
311
360
|
const accountBalances = this.#balances[walletAccount]
|
|
312
361
|
const newBalances = this.#getBalancesFromBlockchainMetadata({
|
|
313
362
|
assetNames: this.#getRelatedAssetNames(assetName),
|
|
314
363
|
accountState,
|
|
315
364
|
txLogsByAssetName,
|
|
365
|
+
feeData,
|
|
316
366
|
})
|
|
317
367
|
|
|
318
368
|
const changes = Object.create(null)
|
|
@@ -375,6 +425,7 @@ const balancesDefinition = {
|
|
|
375
425
|
'balancesAtom',
|
|
376
426
|
'txLogsAtom',
|
|
377
427
|
'accountStatesAtom',
|
|
428
|
+
'feeDataAtom',
|
|
378
429
|
],
|
|
379
430
|
public: true,
|
|
380
431
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/balances",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.10.0",
|
|
4
4
|
"description": "Tracks crypto balances across enabled wallet accounts.",
|
|
5
5
|
"author": "Exodus Movement, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,16 +56,16 @@
|
|
|
56
56
|
"@exodus/assets-feature": "^8.1.2",
|
|
57
57
|
"@exodus/available-assets": "^8.7.0",
|
|
58
58
|
"@exodus/bitcoin-meta": "^2.0.0",
|
|
59
|
-
"@exodus/blockchain-metadata": "^15.
|
|
59
|
+
"@exodus/blockchain-metadata": "^15.12.0",
|
|
60
60
|
"@exodus/ethereum-meta": "^2.0.0",
|
|
61
61
|
"@exodus/fee-data-monitors": "^5.0.4",
|
|
62
62
|
"@exodus/storage-memory": "^2.2.2",
|
|
63
|
-
"@exodus/wallet-accounts": "^17.6.
|
|
63
|
+
"@exodus/wallet-accounts": "^17.6.1",
|
|
64
64
|
"events": "^3.3.0",
|
|
65
65
|
"redux": "^4.2.1"
|
|
66
66
|
},
|
|
67
67
|
"publishConfig": {
|
|
68
68
|
"access": "public"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "067f9209a784784a11412f878443873efaa8f6dc"
|
|
71
71
|
}
|