@exodus/balances 1.2.0 → 2.0.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.
Files changed (2) hide show
  1. package/index.js +82 -35
  2. package/package.json +9 -4
package/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { isNumberUnit } from '@exodus/currency'
2
+ import { TxSet } from '@exodus/models'
2
3
  import ExodusModule from '@exodus/module'
3
4
  import { cloneDeepWith, difference, isEmpty, merge, set, zipObject } from 'lodash'
4
5
  import makeConcurrent from 'make-concurrent'
6
+ import getConfirmedBalance from './confirmed-balance'
5
7
 
6
8
  const cloneBalances = (balances) =>
7
9
  cloneDeepWith(balances, (val) => {
@@ -44,12 +46,13 @@ class Balances extends ExodusModule {
44
46
  this.#handleTxLogUpdate = shareQueue(this.#handleTxLogUpdate)
45
47
  this.#recompute = shareQueue(this.#recompute)
46
48
 
47
- blockchainMetadata.on('loaded', () => {
48
- walletAccountsAtom.observe((payload) =>
49
+ blockchainMetadata.once('load-wallet-accounts', () => {
50
+ walletAccountsAtom.observe((payload) => {
49
51
  this.#setWalletAccounts(
50
52
  Object.keys(payload).filter((walletAccount) => payload[walletAccount].enabled)
51
53
  )
52
- )
54
+ })
55
+
53
56
  blockchainMetadata.on('account-state', this.#handleAccountStateUpdate)
54
57
  blockchainMetadata.on('tx-log', this.#handleTxLogUpdate)
55
58
  })
@@ -58,6 +61,7 @@ class Balances extends ExodusModule {
58
61
  }
59
62
 
60
63
  #getAsset = (assetName) => this.#assetsModule.getAsset(assetName)
64
+ #getAssets = () => this.#assetsModule.getAssets()
61
65
 
62
66
  #handleAccountStateUpdate = async (opts) => {
63
67
  if (!this.#ready) {
@@ -76,7 +80,8 @@ class Balances extends ExodusModule {
76
80
  })
77
81
  return
78
82
  }
79
- if (this.#isHistoryBasedBalanceAsset(opts.assetName)) return this.#updateAssetSource(opts)
83
+
84
+ return this.#updateAssetSource(opts)
80
85
  }
81
86
 
82
87
  #pushIntoSharedQueue = makeConcurrent((fn) => fn(), { concurrency: 1 })
@@ -89,30 +94,47 @@ class Balances extends ExodusModule {
89
94
 
90
95
  #getBalancesForAssetSource = async ({ walletAccount, assetName }) => {
91
96
  const metadata = await this.#loadBlockchainMetadataForBalance({ walletAccount, assetName })
92
- return this.#getBalancesFromBlockchainMetadata({ assetName, ...metadata })
97
+ return this.#getBalancesFromBlockchainMetadata({
98
+ assetNames: this.#getRelatedAssetNames(assetName),
99
+ ...metadata,
100
+ })
93
101
  }
94
102
 
95
- #getBalancesFromBlockchainMetadata = ({ assetName, accountState, txLog }) => {
103
+ #getBalancesFromBlockchainMetadata = ({ assetNames, accountState, txLogsByAssetName }) => {
96
104
  // in the future accountState may have all the balances and we won't need to rely on txLog
97
105
  // for now, accountState-based balance has both the baseAsset and token balances while txLog is per asset/token
98
106
  const getAssetBalances = (assetName) => {
99
107
  const asset = this.#getAsset(assetName)
100
- return asset.api.getBalances({ asset, accountState, txLog })
101
- }
108
+ const txLog = txLogsByAssetName[assetName]
109
+ const balances = asset.api.getBalances({ asset, accountState, txLog })
110
+ if (!balances || isEmpty(balances)) return null
111
+
112
+ if (balances.balance && this.#balanceFields.includes('confirmedBalance')) {
113
+ balances.confirmedBalance = getConfirmedBalance({
114
+ assets: this.#getAssets(),
115
+ asset,
116
+ txLog,
117
+ balance: balances.balance,
118
+ })
119
+ }
120
+
121
+ const negativeBalanceFields = Object.keys(balances).filter(
122
+ (field) => balances[field]?.isNegative
123
+ )
124
+
125
+ if (negativeBalanceFields.length > 0) {
126
+ this._logger.warn('unexpected negative balance', {
127
+ assetName,
128
+ accountState,
129
+ txLogsByAssetName,
130
+ balances,
131
+ negativeBalanceFields,
132
+ })
133
+ }
102
134
 
103
- if (this.#isHistoryBasedBalanceAsset(assetName)) {
104
- const balances = getAssetBalances(assetName)
105
135
  return balances
106
- ? {
107
- [assetName]: balances,
108
- }
109
- : {}
110
136
  }
111
137
 
112
- const assetNames = [assetName, ...this.#assetsModule.getTokenNames(assetName)].filter(
113
- this.#isSupportedAsset
114
- )
115
-
116
138
  const balances = assetNames.map(getAssetBalances)
117
139
  return zipNonNull(assetNames, balances)
118
140
  }
@@ -160,23 +182,41 @@ class Balances extends ExodusModule {
160
182
  }
161
183
 
162
184
  #isSupportedAsset = (assetName) => !this.#getAsset(assetName).isCombined
163
- #getSupportedAssetNames = () =>
164
- Object.keys(this.#assetsModule.getAssets()).filter(this.#isSupportedAsset)
185
+ #getSupportedAssetNames = () => Object.keys(this.#getAssets()).filter(this.#isSupportedAsset)
165
186
 
166
- #isHistoryBasedBalanceAsset = (assetName) => {
167
- const asset = this.#getAsset(assetName)
168
- return asset.api?.hasFeature('historyBasedBalance')
169
- }
187
+ #getRelatedAssetNames = (assetName) =>
188
+ [assetName, ...this.#assetsModule.getTokenNames(assetName)].filter(this.#isSupportedAsset)
189
+
190
+ #loadBlockchainMetadataForBalance = async ({
191
+ assetName,
192
+ walletAccount,
193
+ accountState: providedAccountState = null,
194
+ txLogsByAssetName: providedTxLogsByAssetName = {},
195
+ }) => {
196
+ const [txLogsByAssetSource, accountState] = await Promise.all([
197
+ this.#blockchainMetadata.getLoadedTxLogs(),
198
+ providedAccountState
199
+ ? Promise.resolve(providedAccountState)
200
+ : this.#blockchainMetadata.getAccountState({
201
+ assetName: this.#getAsset(assetName).baseAsset.name,
202
+ walletAccount,
203
+ }),
204
+ ])
205
+
206
+ const assetNames = this.#getRelatedAssetNames(assetName)
207
+ const txLogsByAssetName = zipObject(
208
+ assetNames,
209
+ assetNames.map(
210
+ (assetName) =>
211
+ providedTxLogsByAssetName[assetName] ||
212
+ txLogsByAssetSource[walletAccount]?.[assetName] ||
213
+ TxSet.EMPTY
214
+ )
215
+ )
170
216
 
171
- #loadBlockchainMetadataForBalance = async ({ assetName, walletAccount, accountState, txLog }) => {
172
217
  return {
173
- accountState:
174
- accountState ||
175
- (await this.#blockchainMetadata.getAccountState({
176
- assetName: this.#getAsset(assetName).baseAsset.name,
177
- walletAccount,
178
- })),
179
- txLog: txLog || (await this.#blockchainMetadata.getTxLog({ assetName, walletAccount })),
218
+ accountState,
219
+ txLogsByAssetName,
180
220
  }
181
221
  }
182
222
 
@@ -193,15 +233,22 @@ class Balances extends ExodusModule {
193
233
  return
194
234
  }
195
235
 
196
- const { accountState, txLog } = await this.#loadBlockchainMetadataForBalance({
236
+ const { accountState, txLogsByAssetName } = await this.#loadBlockchainMetadataForBalance({
197
237
  assetName,
198
238
  walletAccount,
199
239
  accountState: providedAccountState,
200
- txLog: providedTxLog,
240
+ txLogsByAssetName: {
241
+ [assetName]: providedTxLog,
242
+ },
201
243
  })
202
244
 
203
245
  const accountBalances = this.#balances[walletAccount]
204
- const newBalances = this.#getBalancesFromBlockchainMetadata({ assetName, accountState, txLog })
246
+ const newBalances = this.#getBalancesFromBlockchainMetadata({
247
+ assetNames: this.#getRelatedAssetNames(assetName),
248
+ accountState,
249
+ txLogsByAssetName,
250
+ })
251
+
205
252
  const changes = Object.create(null)
206
253
  for (let subAssetName in newBalances) {
207
254
  const { currency } = this.#getAsset(subAssetName)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/balances",
3
- "version": "1.2.0",
3
+ "version": "2.0.0",
4
4
  "description": "balances",
5
5
  "author": "Exodus Movement Inc",
6
6
  "license": "UNLICENSED",
@@ -26,10 +26,15 @@
26
26
  "lodash": "^4.17.21",
27
27
  "make-concurrent": "^4.0.0"
28
28
  },
29
+ "peerDependencies": {
30
+ "@exodus/blockchain-metadata": "^3.0.0"
31
+ },
29
32
  "devDependencies": {
30
- "@exodus/atoms": "^1.0.0",
33
+ "@exodus/atoms": "^2.3.0",
31
34
  "@exodus/basic-utils": "^1.0.0",
32
- "@exodus/models": "^8.9.0"
35
+ "@exodus/blockchain-metadata": "*",
36
+ "@exodus/models": "^8.9.0",
37
+ "@exodus/storage-memory": "*"
33
38
  },
34
- "gitHead": "e99b34358ce40fe70ce2a9cb09c622582d0503c9"
39
+ "gitHead": "d03a2b5e5e85e7ffdd3720b22eee00e49f591824"
35
40
  }