@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.
- package/index.js +82 -35
- 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.
|
|
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
|
-
|
|
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({
|
|
97
|
+
return this.#getBalancesFromBlockchainMetadata({
|
|
98
|
+
assetNames: this.#getRelatedAssetNames(assetName),
|
|
99
|
+
...metadata,
|
|
100
|
+
})
|
|
93
101
|
}
|
|
94
102
|
|
|
95
|
-
#getBalancesFromBlockchainMetadata = ({
|
|
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
|
-
|
|
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
|
-
#
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
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,
|
|
236
|
+
const { accountState, txLogsByAssetName } = await this.#loadBlockchainMetadataForBalance({
|
|
197
237
|
assetName,
|
|
198
238
|
walletAccount,
|
|
199
239
|
accountState: providedAccountState,
|
|
200
|
-
|
|
240
|
+
txLogsByAssetName: {
|
|
241
|
+
[assetName]: providedTxLog,
|
|
242
|
+
},
|
|
201
243
|
})
|
|
202
244
|
|
|
203
245
|
const accountBalances = this.#balances[walletAccount]
|
|
204
|
-
const newBalances = this.#getBalancesFromBlockchainMetadata({
|
|
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": "
|
|
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": "^
|
|
33
|
+
"@exodus/atoms": "^2.3.0",
|
|
31
34
|
"@exodus/basic-utils": "^1.0.0",
|
|
32
|
-
"@exodus/
|
|
35
|
+
"@exodus/blockchain-metadata": "*",
|
|
36
|
+
"@exodus/models": "^8.9.0",
|
|
37
|
+
"@exodus/storage-memory": "*"
|
|
33
38
|
},
|
|
34
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "d03a2b5e5e85e7ffdd3720b22eee00e49f591824"
|
|
35
40
|
}
|