@exodus/balances 13.9.1 → 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 CHANGED
@@ -3,6 +3,16 @@
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
+
6
16
  ## [13.9.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/balances@13.9.0...@exodus/balances@13.9.1) (2025-06-11)
7
17
 
8
18
  ### Performance
package/module/index.js CHANGED
@@ -42,6 +42,7 @@ class Balances {
42
42
  #balancesAtom
43
43
  #accountStatesAtom
44
44
  #txLogsAtom
45
+ #feeDataAtom
45
46
  #enabledWalletAccountsAtom
46
47
  #loaded = false
47
48
  #subscriptions = []
@@ -55,6 +56,7 @@ class Balances {
55
56
  balancesAtom,
56
57
  txLogsAtom,
57
58
  accountStatesAtom,
59
+ feeDataAtom,
58
60
  }) {
59
61
  this.#logger = logger
60
62
  this.#assetsModule = assetsModule
@@ -64,6 +66,7 @@ class Balances {
64
66
  this.#balancesAtom = balancesAtom
65
67
  this.#accountStatesAtom = accountStatesAtom
66
68
  this.#txLogsAtom = txLogsAtom
69
+ this.#feeDataAtom = feeDataAtom
67
70
  this.#enabledWalletAccountsAtom = enabledWalletAccountsAtom
68
71
 
69
72
  const shareQueue =
@@ -87,6 +90,7 @@ class Balances {
87
90
  // these share a queue
88
91
  this.#updateAssetSource = shareQueue(this.#updateAssetSource)
89
92
  this.#handleTxLogUpdate = shareQueue(this.#handleTxLogUpdate)
93
+ this.#handleFeeDataUpdate = shareQueue(this.#handleFeeDataUpdate)
90
94
  this.#recompute = shareQueue(this.#recompute)
91
95
  this.#onAssetsChanged = shareQueue(this.#onAssetsChanged)
92
96
  this.#getBalancesForAssetSource = swallowErrors(this.#getBalancesForAssetSource)
@@ -111,6 +115,16 @@ class Balances {
111
115
  this.#handleTxLogUpdate({ walletAccount, assetName, txLog })
112
116
  )
113
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
+
114
128
  getChanges(this.#availableAssetNamesAtom).observe(({ previous = [], current }) => {
115
129
  this.#availableAssetNames = current
116
130
  const added = difference(current, previous)
@@ -143,6 +157,15 @@ class Balances {
143
157
  return this.#updateAssetSource(opts)
144
158
  }
145
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
+
146
169
  #pushIntoSharedQueue = makeConcurrent((fn) => fn(), { concurrency: 1 })
147
170
 
148
171
  #reset = ({ walletAccounts = this.#walletAccounts } = {}) => {
@@ -162,7 +185,12 @@ class Balances {
162
185
  // It adds both old and new balances to the response.
163
186
  // Ideally, selectors should start using the new ones (total, spendable, etc)
164
187
 
165
- #getBalancesFromBlockchainMetadata = ({ assetNames, accountState, txLogsByAssetName }) => {
188
+ #getBalancesFromBlockchainMetadata = ({
189
+ assetNames,
190
+ accountState,
191
+ feeData,
192
+ txLogsByAssetName,
193
+ }) => {
166
194
  // in the future accountState may have all the balances and we won't need to rely on txLog
167
195
  // for now, accountState-based balance has both the baseAsset and token balances while txLog is per asset/token
168
196
  const getAssetBalances = (assetName) => {
@@ -171,7 +199,7 @@ class Balances {
171
199
 
172
200
  const zero = asset.currency.ZERO
173
201
 
174
- const apiBalances = asset.api.getBalances({ asset, accountState, txLog })
202
+ const apiBalances = asset.api.getBalances({ asset, accountState, txLog, feeData })
175
203
  const balances = processAssetBalances({
176
204
  balanceFieldsConfig: this.#balanceFieldsConfig,
177
205
  balances: apiBalances || Object.create(null),
@@ -259,24 +287,33 @@ class Balances {
259
287
  #loadBlockchainMetadataForBalance = async ({
260
288
  assetName,
261
289
  walletAccount,
290
+ feeData: providedFeeData, // it's optional, undefined when balancesRequireFeeData is disabled
262
291
  accountState: providedAccountState = null,
263
292
  txLogsByAssetName: providedTxLogsByAssetName = {},
264
293
  }) => {
265
294
  const { value: txLogsByAssetSource } = await this.#txLogsAtom.get()
266
295
  let accountState = providedAccountState
296
+
297
+ const baseAsset = this.#getAsset(assetName).baseAsset
298
+
267
299
  if (!accountState) {
268
- const asset = this.#getAsset(assetName).baseAsset
269
- const assetNameToUse = asset.name
300
+ const assetNameToUse = baseAsset.name
270
301
  const { value } = await this.#accountStatesAtom.get()
271
302
  const cached = value[walletAccount]?.[assetNameToUse]
272
303
  if (cached) {
273
304
  accountState = cached
274
305
  } else {
275
- const AccountState = asset.api?.createAccountState?.()
306
+ const AccountState = baseAsset.api?.createAccountState?.()
276
307
  accountState = AccountState?.create()
277
308
  }
278
309
  }
279
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
+
280
317
  const assetNames = this.#getRelatedAssetNames(assetName)
281
318
  const txLogsByAssetName = zipObject(
282
319
  assetNames,
@@ -289,6 +326,7 @@ class Balances {
289
326
  )
290
327
 
291
328
  return {
329
+ feeData,
292
330
  accountState,
293
331
  txLogsByAssetName,
294
332
  }
@@ -299,6 +337,7 @@ class Balances {
299
337
  walletAccount,
300
338
  accountState: providedAccountState,
301
339
  txLog: providedTxLog,
340
+ feeData: providedFeeData,
302
341
  }) => {
303
342
  if (!this.#isSupportedAsset(assetName)) return
304
343
 
@@ -307,20 +346,23 @@ class Balances {
307
346
  return
308
347
  }
309
348
 
310
- const { accountState, txLogsByAssetName } = await this.#loadBlockchainMetadataForBalance({
311
- assetName,
312
- walletAccount,
313
- accountState: providedAccountState,
314
- txLogsByAssetName: {
315
- [assetName]: providedTxLog,
316
- },
317
- })
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
+ })
318
359
 
319
360
  const accountBalances = this.#balances[walletAccount]
320
361
  const newBalances = this.#getBalancesFromBlockchainMetadata({
321
362
  assetNames: this.#getRelatedAssetNames(assetName),
322
363
  accountState,
323
364
  txLogsByAssetName,
365
+ feeData,
324
366
  })
325
367
 
326
368
  const changes = Object.create(null)
@@ -383,6 +425,7 @@ const balancesDefinition = {
383
425
  'balancesAtom',
384
426
  'txLogsAtom',
385
427
  'accountStatesAtom',
428
+ 'feeDataAtom',
386
429
  ],
387
430
  public: true,
388
431
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/balances",
3
- "version": "13.9.1",
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,7 +56,7 @@
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.11.1",
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",
@@ -67,5 +67,5 @@
67
67
  "publishConfig": {
68
68
  "access": "public"
69
69
  },
70
- "gitHead": "7db677f161ff564c5ee65cf8f52f213c24b9624a"
70
+ "gitHead": "067f9209a784784a11412f878443873efaa8f6dc"
71
71
  }