@exodus/balances 12.6.0 → 13.0.0-alpha.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 +6 -0
- package/default-config.js +25 -0
- package/index.js +16 -2
- package/module/balances-utils.js +86 -0
- package/module/index.js +24 -49
- package/package.json +11 -12
- package/redux/multi-account-helper.js +1 -1
- package/redux/selectors/create-balance-selectors.js +43 -0
- package/redux/selectors/get-balance-for-field.js +26 -0
- package/redux/selectors/get-balance-selectors.js +39 -0
- package/redux/selectors/get-balances.js +21 -0
- package/redux/selectors/index.js +8 -0
- package/module/confirmed-balance.js +0 -19
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
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
|
+
## [12.6.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/balances@12.6.0...@exodus/balances@12.6.1) (2024-01-15)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- **balances:** expose assetsWithBalanceCountAtom ([#5398](https://github.com/ExodusMovement/exodus-hydra/issues/5398)) ([37ecfcc](https://github.com/ExodusMovement/exodus-hydra/commit/37ecfcc97995293e018ff96cb9286e3aa6a62599))
|
|
11
|
+
|
|
6
12
|
## [12.6.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/balances@12.5.1...@exodus/balances@12.6.0) (2024-01-12)
|
|
7
13
|
|
|
8
14
|
### Features
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const balanceFieldsConfig = [
|
|
2
|
+
{ name: 'total', legacyName: 'balance', default: 'zero' },
|
|
3
|
+
{ name: 'spendable', legacyName: 'spendableBalance', default: 'total' },
|
|
4
|
+
{ name: 'unconfirmedSent' },
|
|
5
|
+
{ name: 'unconfirmedReceived' },
|
|
6
|
+
{ name: 'unspendable' },
|
|
7
|
+
{ name: 'walletReserve' },
|
|
8
|
+
{ name: 'networkReserve' },
|
|
9
|
+
{ name: 'staking' },
|
|
10
|
+
{ name: 'staked' },
|
|
11
|
+
{ name: 'stakable' },
|
|
12
|
+
{ name: 'unstaking' },
|
|
13
|
+
{ name: 'unstaked' },
|
|
14
|
+
{ name: 'rewards' },
|
|
15
|
+
{ name: 'frozen' },
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
const config = {
|
|
19
|
+
balanceFieldsConfig,
|
|
20
|
+
balanceFields: balanceFieldsConfig
|
|
21
|
+
.flatMap((fieldConfig) => [fieldConfig.name, fieldConfig.legacyName])
|
|
22
|
+
.filter(Boolean), // wallets can reduce the number of exposed fields
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default config
|
package/index.js
CHANGED
|
@@ -3,13 +3,26 @@ import {
|
|
|
3
3
|
balancesAtomDefinition,
|
|
4
4
|
hasBalanceAtomDefinition,
|
|
5
5
|
fundedWalletAccountsAtomDefinition,
|
|
6
|
+
assetsWithBalanceCountAtomDefinition,
|
|
6
7
|
} from './atoms'
|
|
7
8
|
import balancesReportDefinition from './report'
|
|
8
9
|
import { balancesLifecyclePluginDefinition, balancesAnalyticsPluginDefinition } from './plugins'
|
|
9
10
|
import typeforce from '@exodus/typeforce'
|
|
11
|
+
import defaultConfig from './default-config'
|
|
10
12
|
|
|
11
|
-
const balances = (
|
|
12
|
-
|
|
13
|
+
const balances = (walletConfig) => {
|
|
14
|
+
const config = {
|
|
15
|
+
...defaultConfig,
|
|
16
|
+
balanceFields: walletConfig?.balanceFields || defaultConfig.balanceFields,
|
|
17
|
+
}
|
|
18
|
+
typeforce(
|
|
19
|
+
{
|
|
20
|
+
balanceFields: typeforce.arrayOf('String'),
|
|
21
|
+
balanceFieldsConfig: typeforce.arrayOf('Object'),
|
|
22
|
+
},
|
|
23
|
+
config,
|
|
24
|
+
true
|
|
25
|
+
)
|
|
13
26
|
|
|
14
27
|
return {
|
|
15
28
|
id: 'balances',
|
|
@@ -19,6 +32,7 @@ const balances = (config) => {
|
|
|
19
32
|
config,
|
|
20
33
|
},
|
|
21
34
|
{ definition: balancesAtomDefinition },
|
|
35
|
+
{ definition: assetsWithBalanceCountAtomDefinition },
|
|
22
36
|
{
|
|
23
37
|
definition: hasBalanceAtomDefinition,
|
|
24
38
|
storage: { namespace: 'balances' },
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { mapValues } from '@exodus/basic-utils'
|
|
2
|
+
|
|
3
|
+
function resolveFieldBalance({ balances, fieldConfig, zero, processedBalances }) {
|
|
4
|
+
if (balances[fieldConfig.name]) {
|
|
5
|
+
return balances[fieldConfig.name]
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (fieldConfig.legacyName && balances[fieldConfig.legacyName]) {
|
|
9
|
+
return balances[fieldConfig.legacyName]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (fieldConfig.default && fieldConfig.default === 'zero') {
|
|
13
|
+
return zero
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (fieldConfig.default && processedBalances[fieldConfig.default] !== null) {
|
|
17
|
+
if (processedBalances[fieldConfig.default] === undefined) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`Field config "${fieldConfig.default}" must be defined before "${fieldConfig.name}"`
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return processedBalances[fieldConfig.default]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const processAssetBalances = ({ balances, zero, balanceFieldsConfig }) => {
|
|
30
|
+
return balanceFieldsConfig.reduce((processedBalances, fieldConfig) => {
|
|
31
|
+
const balance = resolveFieldBalance({
|
|
32
|
+
balances,
|
|
33
|
+
fieldConfig,
|
|
34
|
+
zero,
|
|
35
|
+
processedBalances,
|
|
36
|
+
})
|
|
37
|
+
if (balance !== null) {
|
|
38
|
+
processedBalances[fieldConfig.name] = balance
|
|
39
|
+
if (fieldConfig.legacyName) {
|
|
40
|
+
processedBalances[fieldConfig.legacyName] = balance
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return processedBalances
|
|
45
|
+
}, {})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const validateBalances = ({ balances, asset, logger }) => {
|
|
49
|
+
const assetName = asset.name
|
|
50
|
+
const zero = asset.currency.ZERO
|
|
51
|
+
|
|
52
|
+
const log = (error) => {
|
|
53
|
+
logger.warn(error.fn, error.error, error.args)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return mapValues(balances, (balance, field) => {
|
|
57
|
+
if (!balance) {
|
|
58
|
+
return balance
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!balance.unitType.equals(asset.currency)) {
|
|
62
|
+
log({
|
|
63
|
+
fn: 'getAssetBalances',
|
|
64
|
+
error: `asset.api.getBalances ${assetName} returns different ${field} currency`,
|
|
65
|
+
args: {
|
|
66
|
+
balanceUnit: balance.unitType.defaultUnit.unitName,
|
|
67
|
+
assetUnit: asset.currency.defaultUnit.unitName,
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
return zero
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (balance.isNegative) {
|
|
74
|
+
log({
|
|
75
|
+
fn: 'getAssetBalances',
|
|
76
|
+
error: `asset.api.getBalances ${assetName} returns negative ${field}`,
|
|
77
|
+
args: {
|
|
78
|
+
amount: balance.toDefaultString({ unit: true }),
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
return zero
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return balance
|
|
85
|
+
})
|
|
86
|
+
}
|
package/module/index.js
CHANGED
|
@@ -2,9 +2,10 @@ import { isNumberUnit } from '@exodus/currency'
|
|
|
2
2
|
import { TxSet } from '@exodus/models'
|
|
3
3
|
import ExodusModule from '@exodus/module'
|
|
4
4
|
import { cloneDeepWith, isEmpty, merge, set, zipObject } from 'lodash'
|
|
5
|
-
import { difference, flattenToPaths } from '@exodus/basic-utils'
|
|
5
|
+
import { difference, flattenToPaths, pick } from '@exodus/basic-utils'
|
|
6
6
|
import makeConcurrent from 'make-concurrent'
|
|
7
|
-
import
|
|
7
|
+
import { processAssetBalances, validateBalances } from './balances-utils'
|
|
8
|
+
import defaultConfig from '../default-config'
|
|
8
9
|
|
|
9
10
|
const cloneBalances = (balances) =>
|
|
10
11
|
cloneDeepWith(balances, (val) => {
|
|
@@ -22,6 +23,7 @@ export const MODULE_ID = 'balances'
|
|
|
22
23
|
class Balances extends ExodusModule {
|
|
23
24
|
#assetsModule
|
|
24
25
|
#assetsAtom
|
|
26
|
+
#balanceFieldsConfig
|
|
25
27
|
#balanceFields
|
|
26
28
|
#walletAccounts = [] // string[]
|
|
27
29
|
#ready = false
|
|
@@ -38,7 +40,7 @@ class Balances extends ExodusModule {
|
|
|
38
40
|
assetsModule,
|
|
39
41
|
assetsAtom,
|
|
40
42
|
enabledWalletAccountsAtom,
|
|
41
|
-
config
|
|
43
|
+
config,
|
|
42
44
|
logger,
|
|
43
45
|
balancesAtom,
|
|
44
46
|
txLogsAtom,
|
|
@@ -48,7 +50,8 @@ class Balances extends ExodusModule {
|
|
|
48
50
|
|
|
49
51
|
this.#assetsModule = assetsModule
|
|
50
52
|
this.#assetsAtom = assetsAtom
|
|
51
|
-
this.#
|
|
53
|
+
this.#balanceFieldsConfig = config?.balanceFieldsConfig || defaultConfig.balanceFieldsConfig
|
|
54
|
+
this.#balanceFields = config?.balanceFields || defaultConfig.balanceFields
|
|
52
55
|
this.#balancesAtom = balancesAtom
|
|
53
56
|
this.#accountStatesAtom = accountStatesAtom
|
|
54
57
|
this.#txLogsAtom = txLogsAtom
|
|
@@ -160,59 +163,31 @@ class Balances extends ExodusModule {
|
|
|
160
163
|
})
|
|
161
164
|
}
|
|
162
165
|
|
|
166
|
+
// It adds both old and new balances to the response.
|
|
167
|
+
// Ideally, selectors should start using the new ones (total, spendable, etc)
|
|
168
|
+
|
|
163
169
|
#getBalancesFromBlockchainMetadata = ({ assetNames, accountState, txLogsByAssetName }) => {
|
|
164
170
|
// in the future accountState may have all the balances and we won't need to rely on txLog
|
|
165
171
|
// for now, accountState-based balance has both the baseAsset and token balances while txLog is per asset/token
|
|
166
172
|
const getAssetBalances = (assetName) => {
|
|
167
173
|
const asset = this.#getAsset(assetName)
|
|
168
174
|
const txLog = txLogsByAssetName[assetName]
|
|
169
|
-
const balances = asset.api.getBalances({ asset, accountState, txLog })
|
|
170
|
-
if (!balances || isEmpty(balances) || !balances.balance)
|
|
171
|
-
return Object.fromEntries(this.#balanceFields.map((field) => [field, asset.currency.ZERO]))
|
|
172
|
-
if (!balances.balance.unitType.equals(asset.currency)) {
|
|
173
|
-
this.emit('error', {
|
|
174
|
-
fn: 'getAssetBalances',
|
|
175
|
-
error: 'asset.api.getBalances returns different currency',
|
|
176
|
-
args: {
|
|
177
|
-
balanceUnit: balances.balance.unitType.defaultUnit.unitName,
|
|
178
|
-
assetUnit: asset.currency.defaultUnit.unitName,
|
|
179
|
-
},
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
this._logger.warn(
|
|
183
|
-
'asset.api.getBalances returns different currency, asset currency:',
|
|
184
|
-
asset.currency.defaultUnit.unitName,
|
|
185
|
-
'balance currency',
|
|
186
|
-
balances.balance.unitType.defaultUnit.unitName,
|
|
187
|
-
'return zero balance for it'
|
|
188
|
-
)
|
|
189
175
|
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (balances.balance && this.#balanceFields.includes('confirmedBalance')) {
|
|
194
|
-
balances.confirmedBalance = getConfirmedBalance({
|
|
195
|
-
asset,
|
|
196
|
-
txLog,
|
|
197
|
-
balance: balances.balance,
|
|
198
|
-
})
|
|
199
|
-
}
|
|
176
|
+
const zero = asset.currency.ZERO
|
|
200
177
|
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return balances
|
|
178
|
+
const apiBalances = asset.api.getBalances({ asset, accountState, txLog })
|
|
179
|
+
const balances = processAssetBalances({
|
|
180
|
+
balanceFieldsConfig: this.#balanceFieldsConfig,
|
|
181
|
+
balances: apiBalances || {},
|
|
182
|
+
zero,
|
|
183
|
+
})
|
|
184
|
+
return validateBalances({
|
|
185
|
+
balances: pick(balances, this.#balanceFields),
|
|
186
|
+
asset,
|
|
187
|
+
zero,
|
|
188
|
+
logger: this._logger,
|
|
189
|
+
emitter: this,
|
|
190
|
+
})
|
|
216
191
|
}
|
|
217
192
|
|
|
218
193
|
const balances = assetNames.map(getAssetBalances)
|
package/package.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/balances",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0-alpha.0",
|
|
4
4
|
"description": "Tracks crypto balances across enabled wallet accounts.",
|
|
5
5
|
"author": "Exodus Movement Inc.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"test": "jest",
|
|
9
|
-
"lint": "eslint . --ignore-path ../../.gitignore",
|
|
8
|
+
"test": "run -T jest",
|
|
9
|
+
"lint": "run -T eslint . --ignore-path ../../.gitignore",
|
|
10
10
|
"lint:fix": "yarn lint --fix"
|
|
11
11
|
},
|
|
12
12
|
"main": "index.js",
|
|
13
13
|
"files": [
|
|
14
14
|
"module",
|
|
15
15
|
"atoms",
|
|
16
|
+
"default-config.js",
|
|
16
17
|
"report",
|
|
17
18
|
"plugins",
|
|
18
19
|
"redux",
|
|
@@ -29,12 +30,13 @@
|
|
|
29
30
|
"url": "https://github.com/ExodusMovement/exodus-hydra/issues?q=is%3Aissue+is%3Aopen+label%3Abalances"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"@exodus/atoms": "
|
|
33
|
+
"@exodus/atoms": "workspace:^",
|
|
33
34
|
"@exodus/basic-utils": "^2.1.0",
|
|
34
35
|
"@exodus/currency": "^2.1.2",
|
|
35
36
|
"@exodus/models": "^10.1.0",
|
|
36
37
|
"@exodus/module": "^1.1.0",
|
|
37
|
-
"@exodus/multi-account-redux": "
|
|
38
|
+
"@exodus/multi-account-redux": "workspace:^",
|
|
39
|
+
"@exodus/redux-dependency-injection": "workspace:^",
|
|
38
40
|
"@exodus/typeforce": "^1.18.0",
|
|
39
41
|
"lodash": "^4.17.21",
|
|
40
42
|
"make-concurrent": "^4.0.0",
|
|
@@ -46,17 +48,14 @@
|
|
|
46
48
|
"devDependencies": {
|
|
47
49
|
"@exodus/assets": "^8.0.94",
|
|
48
50
|
"@exodus/assets-base": "^8.1.10",
|
|
49
|
-
"@exodus/assets-feature": "
|
|
51
|
+
"@exodus/assets-feature": "workspace:^",
|
|
50
52
|
"@exodus/bitcoin-meta": "^1.0.1",
|
|
51
53
|
"@exodus/blockchain-metadata": "^9.0.1",
|
|
52
54
|
"@exodus/ethereum-meta": "^1.0.30",
|
|
53
|
-
"@exodus/redux-dependency-injection": "
|
|
55
|
+
"@exodus/redux-dependency-injection": "workspace:^",
|
|
54
56
|
"@exodus/storage-memory": "*",
|
|
55
|
-
"@exodus/wallet-accounts": "
|
|
56
|
-
"eslint": "^8.44.0",
|
|
57
|
+
"@exodus/wallet-accounts": "workspace:^",
|
|
57
58
|
"events": "^3.3.0",
|
|
58
|
-
"jest": "^29.1.2",
|
|
59
59
|
"redux": "^4.2.1"
|
|
60
|
-
}
|
|
61
|
-
"gitHead": "873f103b45c562e5fd3369a30bfb7c7e95363efa"
|
|
60
|
+
}
|
|
62
61
|
}
|
|
@@ -6,7 +6,7 @@ const helper = createReduxModuleHelper({
|
|
|
6
6
|
createInitialPerAssetData: ({ asset }) => {
|
|
7
7
|
return { balance: asset.currency.ZERO }
|
|
8
8
|
},
|
|
9
|
-
assetSourceDataSelectors: [{ name: 'balance', selector: (assetData) => assetData.
|
|
9
|
+
assetSourceDataSelectors: [{ name: 'balance', selector: (assetData) => assetData.total }],
|
|
10
10
|
})
|
|
11
11
|
|
|
12
12
|
export default helper
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { memoize } from 'lodash'
|
|
2
|
+
import { MY_STATE } from '@exodus/redux-dependency-injection'
|
|
3
|
+
import { createSelector } from 'reselect'
|
|
4
|
+
|
|
5
|
+
const createBalanceSelectorFactory = ({ field, id }) => {
|
|
6
|
+
const selectorFactory = (selfSelector) =>
|
|
7
|
+
memoize(
|
|
8
|
+
({ assetName, walletAccount }) =>
|
|
9
|
+
createSelector(
|
|
10
|
+
selfSelector,
|
|
11
|
+
(balances) => balances[walletAccount]?.data[assetName]?.[field]
|
|
12
|
+
),
|
|
13
|
+
({ assetName, walletAccount, field }) => [assetName, walletAccount, field].join('-')
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
id,
|
|
18
|
+
selectorFactory,
|
|
19
|
+
dependencies: [{ selector: MY_STATE }],
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const createBalanceSelectors = [
|
|
24
|
+
// regenerate if there is a new balance field!!
|
|
25
|
+
{ id: 'createTotal', field: 'total' },
|
|
26
|
+
{ id: 'createBalance', field: 'balance' },
|
|
27
|
+
{ id: 'createSpendable', field: 'spendable' },
|
|
28
|
+
{ id: 'createSpendableBalance', field: 'spendableBalance' },
|
|
29
|
+
{ id: 'createUnconfirmedSent', field: 'unconfirmedSent' },
|
|
30
|
+
{ id: 'createUnconfirmedReceived', field: 'unconfirmedReceived' },
|
|
31
|
+
{ id: 'createUnspendable', field: 'unspendable' },
|
|
32
|
+
{ id: 'createWalletReserve', field: 'walletReserve' },
|
|
33
|
+
{ id: 'createNetworkReserve', field: 'networkReserve' },
|
|
34
|
+
{ id: 'createStaking', field: 'staking' },
|
|
35
|
+
{ id: 'createStaked', field: 'staked' },
|
|
36
|
+
{ id: 'createStakable', field: 'stakable' },
|
|
37
|
+
{ id: 'createUnstaking', field: 'unstaking' },
|
|
38
|
+
{ id: 'createUnstaked', field: 'unstaked' },
|
|
39
|
+
{ id: 'createRewards', field: 'rewards' },
|
|
40
|
+
{ id: 'createFrozen', field: 'frozen' },
|
|
41
|
+
].map(createBalanceSelectorFactory)
|
|
42
|
+
|
|
43
|
+
export default createBalanceSelectors
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { memoize } from 'lodash'
|
|
2
|
+
import defaultConfig from '../../default-config'
|
|
3
|
+
|
|
4
|
+
const { balanceFields } = defaultConfig
|
|
5
|
+
|
|
6
|
+
const resultFunction = (getBalances) =>
|
|
7
|
+
memoize(
|
|
8
|
+
({ assetName, walletAccount, field }) => {
|
|
9
|
+
if (!balanceFields.includes(field)) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
`Value '${field}' is not one of the valid fields '${balanceFields.join(', ')}'`
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return getBalances({ assetName, walletAccount })?.[field]
|
|
16
|
+
},
|
|
17
|
+
({ assetName, walletAccount, field }) => [assetName, walletAccount, field].join('-')
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
const getBalanceForFieldSelectorDefinition = {
|
|
21
|
+
id: 'getBalanceForField',
|
|
22
|
+
resultFunction,
|
|
23
|
+
dependencies: [{ module: 'balances', selector: 'getBalances' }],
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default getBalanceForFieldSelectorDefinition
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { memoize } from 'lodash'
|
|
2
|
+
|
|
3
|
+
const createResultFunction = (field) => (getBalanceForField) =>
|
|
4
|
+
memoize(
|
|
5
|
+
({ assetName, walletAccount }) => {
|
|
6
|
+
return getBalanceForField({ assetName, walletAccount, field })
|
|
7
|
+
},
|
|
8
|
+
({ assetName, walletAccount }) => [assetName, walletAccount].join('-')
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
const getBalanceSelectorFactory = ({ field, id }) => {
|
|
12
|
+
return {
|
|
13
|
+
id,
|
|
14
|
+
resultFunction: createResultFunction(field),
|
|
15
|
+
dependencies: [{ module: 'balances', selector: 'getBalanceForField' }],
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const getBalanceSelectors = [
|
|
20
|
+
// regenerate if there is a new balance field!!
|
|
21
|
+
{ id: 'getTotal', field: 'total' },
|
|
22
|
+
{ id: 'getBalance', field: 'balance' },
|
|
23
|
+
{ id: 'getSpendable', field: 'spendable' },
|
|
24
|
+
{ id: 'getSpendableBalance', field: 'spendableBalance' },
|
|
25
|
+
{ id: 'getUnconfirmedSent', field: 'unconfirmedSent' },
|
|
26
|
+
{ id: 'getUnconfirmedReceived', field: 'unconfirmedReceived' },
|
|
27
|
+
{ id: 'getUnspendable', field: 'unspendable' },
|
|
28
|
+
{ id: 'getWalletReserve', field: 'walletReserve' },
|
|
29
|
+
{ id: 'getNetworkReserve', field: 'networkReserve' },
|
|
30
|
+
{ id: 'getStaking', field: 'staking' },
|
|
31
|
+
{ id: 'getStaked', field: 'staked' },
|
|
32
|
+
{ id: 'getStakable', field: 'stakable' },
|
|
33
|
+
{ id: 'getUnstaking', field: 'unstaking' },
|
|
34
|
+
{ id: 'getUnstaked', field: 'unstaked' },
|
|
35
|
+
{ id: 'getRewards', field: 'rewards' },
|
|
36
|
+
{ id: 'getFrozen', field: 'frozen' },
|
|
37
|
+
].map(getBalanceSelectorFactory)
|
|
38
|
+
|
|
39
|
+
export default getBalanceSelectors
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { memoize } from 'lodash'
|
|
2
|
+
import { createSelector } from 'reselect'
|
|
3
|
+
import { MY_STATE } from '@exodus/redux-dependency-injection'
|
|
4
|
+
|
|
5
|
+
const selectorFactory = (selfSelector) =>
|
|
6
|
+
createSelector(selfSelector, (balances) =>
|
|
7
|
+
memoize(
|
|
8
|
+
({ assetName, walletAccount }) => {
|
|
9
|
+
return balances[walletAccount]?.data[assetName]
|
|
10
|
+
},
|
|
11
|
+
({ assetName, walletAccount }) => [assetName, walletAccount].join('-')
|
|
12
|
+
)
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
const getBalancesSelectorDefinition = {
|
|
16
|
+
id: 'getBalances',
|
|
17
|
+
selectorFactory,
|
|
18
|
+
dependencies: [{ selector: MY_STATE }],
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default getBalancesSelectorDefinition
|
package/redux/selectors/index.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import byAssetSelectorDefinition from './by-asset'
|
|
2
2
|
import createUnconfirmedBalanceSelectorDefinition from './create-unconfirmed-balance'
|
|
3
|
+
import getBalanceForFieldSelectorDefinition from './get-balance-for-field'
|
|
4
|
+
import getBalanceSelectors from './get-balance-selectors'
|
|
5
|
+
import getBalancesSelectorDefinition from './get-balances'
|
|
6
|
+
import createBalancesSelectors from './create-balance-selectors'
|
|
3
7
|
import getUnconfirmedBalanceSelectorDefinition from './get-unconfirmed-balance'
|
|
4
8
|
|
|
5
9
|
export default [
|
|
6
10
|
byAssetSelectorDefinition,
|
|
7
11
|
createUnconfirmedBalanceSelectorDefinition,
|
|
12
|
+
getBalanceForFieldSelectorDefinition,
|
|
13
|
+
...getBalanceSelectors,
|
|
14
|
+
...createBalancesSelectors,
|
|
15
|
+
getBalancesSelectorDefinition,
|
|
8
16
|
getUnconfirmedBalanceSelectorDefinition,
|
|
9
17
|
]
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { TxSet } from '@exodus/models'
|
|
2
|
-
|
|
3
|
-
const isUnconfirmedTx = (tx) => tx.pending && !tx.error
|
|
4
|
-
|
|
5
|
-
const getTxSetBalance = (txSet) => txSet.getMutations().slice(-1)[0].balance
|
|
6
|
-
|
|
7
|
-
const getUnconfirmedTotal = ({ asset, txLog }) => {
|
|
8
|
-
const unconfirmedTxs = [...txLog].filter(isUnconfirmedTx)
|
|
9
|
-
return unconfirmedTxs.length === 0
|
|
10
|
-
? asset.currency.ZERO
|
|
11
|
-
: getTxSetBalance(TxSet.fromArray(unconfirmedTxs))
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const getConfirmedBalance = ({ asset, txLog, balance }) => {
|
|
15
|
-
const unconfirmedTotal = getUnconfirmedTotal({ asset, txLog })
|
|
16
|
-
return balance.sub(unconfirmedTotal)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export default getConfirmedBalance
|