@exodus/activity-txs 4.0.1 → 4.1.1

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,27 @@
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
+ ## [4.1.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/activity-txs@4.1.0...@exodus/activity-txs@4.1.1) (2024-05-15)
7
+
8
+ ### Bug Fixes
9
+
10
+ - duplicated activity items for transfers ([#6931](https://github.com/ExodusMovement/exodus-hydra/issues/6931)) ([7d2acb6](https://github.com/ExodusMovement/exodus-hydra/commit/7d2acb63b3151b9703243349e256b1db52613b43))
11
+
12
+ ## [4.1.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/activity-txs@4.0.1...@exodus/activity-txs@4.1.0) (2024-05-13)
13
+
14
+ ### Features
15
+
16
+ - activity base selector ([#6712](https://github.com/ExodusMovement/exodus-hydra/issues/6712)) ([929a87c](https://github.com/ExodusMovement/exodus-hydra/commit/929a87ce359195aafb177248eed3f0c4fe544452))
17
+ - add withFiat selector ([#6766](https://github.com/ExodusMovement/exodus-hydra/issues/6766)) ([10c9aaf](https://github.com/ExodusMovement/exodus-hydra/commit/10c9aaf8e28c2ad13885e4f1c5d8ff6f345d6508))
18
+ - connections activity selector ([#6855](https://github.com/ExodusMovement/exodus-hydra/issues/6855)) ([37bc022](https://github.com/ExodusMovement/exodus-hydra/commit/37bc0221be3a6c536b0fbf5f6ee22b06e084667d))
19
+ - full activity selector ([#6861](https://github.com/ExodusMovement/exodus-hydra/issues/6861)) ([7d0d168](https://github.com/ExodusMovement/exodus-hydra/commit/7d0d1689c37e14169a24fd73670183c282f0ad41))
20
+ - multi activity ([#6870](https://github.com/ExodusMovement/exodus-hydra/issues/6870)) ([7d72596](https://github.com/ExodusMovement/exodus-hydra/commit/7d72596b9718511f5e3ca43f4b36a5890a7b6b76))
21
+ - withNfts selectors ([#6765](https://github.com/ExodusMovement/exodus-hydra/issues/6765)) ([1f6d3d6](https://github.com/ExodusMovement/exodus-hydra/commit/1f6d3d668c32b184ca26cdbbb47c418c007ea7a1))
22
+
23
+ ### Bug Fixes
24
+
25
+ - missing dependencies ([#5322](https://github.com/ExodusMovement/exodus-hydra/issues/5322)) ([01efedc](https://github.com/ExodusMovement/exodus-hydra/commit/01efedc7508fb14925277fdcd388afb721ac3dd1))
26
+
6
27
  ## [4.0.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/activity-txs@4.0.0...@exodus/activity-txs@4.0.1) (2023-12-20)
7
28
 
8
29
  ### Bug Fixes
package/README.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @exodus/activity-txs
2
2
 
3
+ Activity consists of a set of asset transactions that are transformed using `asset.api.getActivityTxs`
4
+ which returns Array of Tx [models](https://github.com/ExodusMovement/exodus-core/blob/cdff25bb962b2301613588c615c5ac09b05f260a/packages/models/src/tx/index.js#L10): `[Tx, Tx, Tx]`
5
+ Most of the assets don't have this api and simply return original txs.
6
+ An example of this transformation is combining bitcoin batched transactions into a single activity item, instead of multiple Txs you get single Tx with adjusted `coinAmount`.
7
+ These are utilized in the UI to display transaction history.
8
+
9
+ This feature introduces atoms with activity items generated from txLog and accountState.
10
+ It provides an efficient way to store them by wallet accounts and to update this extensive object while avoiding unnecessary re-computations.
11
+ Additionally, it offers extra redux selectors to retrieve activity limited by size or batched activity items.
12
+
3
13
  ## Usage
4
14
 
5
- ioc.use(activityTxs())
15
+ `ioc.use(activityTxs())`
16
+
17
+ selector example to get batched activity for specific asset from specific account:
18
+ `selectors.activityTxs.createBatchedAssetSourceSelector({ assetName, walletAccount })` return array of txs `[Tx, Tx, ...]`
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@exodus/activity-txs",
3
- "version": "4.0.1",
3
+ "version": "4.1.1",
4
4
  "description": "The activity-txs feature",
5
- "author": "Exodus Movement Inc.",
5
+ "author": "Exodus Movement, Inc.",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/ExodusMovement/exodus-hydra.git"
@@ -25,35 +25,40 @@
25
25
  "!**/*.test.js"
26
26
  ],
27
27
  "scripts": {
28
- "lint": "eslint . --ignore-path ../../.gitignore",
28
+ "lint": "run -T eslint . --ignore-path ../../.gitignore",
29
29
  "lint:fix": "yarn lint --fix",
30
- "test": "jest"
30
+ "test": "run -T jest"
31
31
  },
32
32
  "dependencies": {
33
- "@exodus/atoms": "^7.0.0",
34
- "@exodus/basic-utils": "^2.1.0",
33
+ "@exodus/atoms": "^7.0.5",
34
+ "@exodus/basic-utils": "^2.3.0",
35
35
  "@exodus/core-selectors": "^1.5.0",
36
+ "@exodus/models": "^10.1.0",
36
37
  "@exodus/module": "^1.2.2",
37
38
  "@exodus/multi-account-redux": "^2.0.1",
38
39
  "lodash": "^4.17.21",
40
+ "minimalistic-assert": "^1.0.1",
39
41
  "reselect": "^3.0.1"
40
42
  },
41
43
  "devDependencies": {
42
44
  "@exodus/assets": "^8.0.95",
43
45
  "@exodus/assets-base": "^8.1.10",
44
- "@exodus/assets-feature": "^4.0.1",
46
+ "@exodus/assets-feature": "^5.3.1",
47
+ "@exodus/available-assets": "^8.2.0",
45
48
  "@exodus/bitcoin-plugin": "^1.4.2",
46
- "@exodus/blockchain-metadata": "^15.0.0",
47
- "@exodus/dependency-injection": "^2.1.0",
48
- "@exodus/dependency-preprocessors": "^4.1.0",
49
- "@exodus/models": "^10.1.0",
49
+ "@exodus/blockchain-metadata": "^15.3.1",
50
+ "@exodus/connected-origins": "^3.3.1",
51
+ "@exodus/dependency-injection": "^2.2.0",
52
+ "@exodus/dependency-preprocessors": "^5.2.0",
53
+ "@exodus/fiat-ramp": "^10.5.1",
54
+ "@exodus/nfts": "^9.2.1",
55
+ "@exodus/orders": "^4.8.1",
50
56
  "@exodus/personal-notes": "^3.6.0",
51
- "@exodus/redux-dependency-injection": "^3.0.0",
57
+ "@exodus/redux-dependency-injection": "^3.1.0",
52
58
  "@exodus/storage-memory": "^2.1.1",
53
- "@exodus/wallet-accounts": "^15.0.0",
54
- "eslint": "^8.44.0",
55
- "jest": "^29.1.2",
59
+ "@exodus/wallet-accounts": "^16.5.0",
60
+ "@types/minimalistic-assert": "^1.0.1",
56
61
  "redux": "^4.2.1"
57
62
  },
58
- "gitHead": "f9da7e1a0be705cb2faace4af6ea2b4a69b4fd0f"
63
+ "gitHead": "268f3e822c0d1aadc8a42391b9770b435021e230"
59
64
  }
@@ -0,0 +1,9 @@
1
+ export const TX_TYPES = {
2
+ EXCHANGE: 'exchange',
3
+ FIAT: 'fiat',
4
+ RECEIVED: 'rx',
5
+ SENT: 'tx',
6
+ APPROVAL: 'approval',
7
+ CLEANUP: 'cleanup',
8
+ NFT: 'nft',
9
+ }
@@ -0,0 +1,126 @@
1
+ import { createSelector } from 'reselect'
2
+ import { memoize } from '@exodus/basic-utils'
3
+ import { TX_TYPES } from '../constants/tx-types'
4
+ import { formatGroupedExchangeTxs, formattersByType } from '../utils/formatters'
5
+
6
+ const EMPTY = Object.freeze([])
7
+
8
+ const generateActivityId = ({ activityItem }) => {
9
+ const sentIndex = activityItem.data?.sentIndex
10
+ return sentIndex
11
+ ? `${activityItem.assetName}.${activityItem.txId}_${sentIndex}`
12
+ : `${activityItem.assetName}.${activityItem.txId}`
13
+ }
14
+
15
+ const groupTxsWithSameOrder = ({ txs, orderSet }) => {
16
+ const getOrder = (tx) => orderSet.getByTxId(tx.txId)
17
+ const exchangeByOrderId = {}
18
+ const result = []
19
+ for (const tx of txs) {
20
+ const order = getOrder(tx)
21
+ if (order) {
22
+ ;(exchangeByOrderId[order.orderId] ?? (exchangeByOrderId[order.orderId] = [])).push(tx)
23
+ } else {
24
+ result.push({ tx, type: 'tx' })
25
+ }
26
+ }
27
+
28
+ Object.values(exchangeByOrderId).forEach((txsGroup) => {
29
+ const tx = txsGroup.sort((a, b) => b.date.getTime() - a.date.getTime())[0]
30
+ const order = getOrder(tx)
31
+ result.push({ tx, type: 'exchange', order })
32
+ })
33
+ return result
34
+ }
35
+
36
+ const createAssetSourceBaseActivitySelectorDefinition = {
37
+ id: 'createAssetSourceBaseActivity',
38
+ selectorFactory: (
39
+ assetsSelector,
40
+ createBatchedAssetSourceSelector,
41
+ createOrdersInAccountSelector,
42
+ getPersonalNoteByTxIdSelector
43
+ ) =>
44
+ memoize(
45
+ ({ assetName, walletAccount }) =>
46
+ createSelector(
47
+ assetsSelector,
48
+ createBatchedAssetSourceSelector({ assetName, walletAccount }),
49
+ createOrdersInAccountSelector(walletAccount),
50
+ getPersonalNoteByTxIdSelector,
51
+ (assets, txs = EMPTY, orderSet, getPersonalNoteByTxId) => {
52
+ const activityResult = []
53
+
54
+ const groupedTxs = groupTxsWithSameOrder({ txs, orderSet })
55
+
56
+ for (const group of groupedTxs) {
57
+ const { tx, order, type: formatterType } = group
58
+ const personalNote = getPersonalNoteByTxId(tx.txId)
59
+ const formattedTx = formattersByType[formatterType]({
60
+ assets,
61
+ order,
62
+ tx,
63
+ personalNote,
64
+ })
65
+ formattedTx.id = generateActivityId({ activityItem: formattedTx })
66
+
67
+ activityResult.push(formattedTx)
68
+ }
69
+
70
+ const isIndexless = assets[assetName]?.baseAsset?.api?.features?.noHistory
71
+ if (isIndexless) {
72
+ const orderIdsFromActivity = new Set(activityResult.map((tx) => tx.orderId))
73
+ const ordersForIndexlessAssets = [...orderSet].filter(
74
+ (order) =>
75
+ [order.fromAsset, order.toAsset].includes(assetName) &&
76
+ order.exodusStatus !== 'syncing'
77
+ )
78
+
79
+ ordersForIndexlessAssets.forEach((order) => {
80
+ // Prevent dups by checking if this order already exists.
81
+ if (orderIdsFromActivity.has(order.orderId)) return
82
+
83
+ const isFromIndexlessAsset = order.fromAsset === assetName
84
+ const formattedItem = formatGroupedExchangeTxs({
85
+ tx: {
86
+ type: TX_TYPES.EXCHANGE,
87
+ date: order.date,
88
+ order,
89
+ pending: !['failed-final', 'complete-verified'].includes(order.status),
90
+ failed: order.status === 'failed-final',
91
+ data: { swapTx: true },
92
+ selfSend: false,
93
+ token: null, // TBD
94
+ bumpType: {},
95
+ coinName: isFromIndexlessAsset ? order.fromAsset : order.toAsset,
96
+ value: isFromIndexlessAsset ? order.fromAmount : order.toAmount,
97
+ coinAmount: isFromIndexlessAsset ? order.fromAmount : order.toAmount,
98
+ txId: isFromIndexlessAsset ? order.fromTxId : order.toTxId,
99
+ sent: isFromIndexlessAsset,
100
+ received: !isFromIndexlessAsset,
101
+ },
102
+ assets,
103
+ order,
104
+ })
105
+
106
+ formattedItem.id = generateActivityId({ activityItem: formattedItem })
107
+ activityResult.push(formattedItem)
108
+ })
109
+ }
110
+
111
+ if (activityResult.length === 0) return EMPTY
112
+
113
+ return activityResult.sort((a, b) => b.date.getTime() - a.date.getTime())
114
+ }
115
+ ),
116
+ ({ assetName, walletAccount }) => `${assetName}_${walletAccount}`
117
+ ),
118
+ dependencies: [
119
+ { module: 'assets', selector: 'all' },
120
+ { selector: 'createBatchedAssetSourceSelector' },
121
+ { module: 'orders', selector: 'createOrdersInAccount' },
122
+ { module: 'personalNotes', selector: 'get' },
123
+ ],
124
+ }
125
+
126
+ export default createAssetSourceBaseActivitySelectorDefinition
@@ -0,0 +1,34 @@
1
+ const selectorFactory =
2
+ (
3
+ createAssetSourceBaseActivity,
4
+ createWithFiatActivity,
5
+ createWithNftsActivity,
6
+ createWithConnectionsActivity
7
+ ) =>
8
+ // call this once on client-side
9
+ (options = {}) => {
10
+ let createFullSelector = createAssetSourceBaseActivity
11
+ createFullSelector = createWithNftsActivity({
12
+ createActivitySelector: createFullSelector,
13
+ nftsNetworkNameToAssetName: options.nftsNetworkNameToAssetName || {},
14
+ })
15
+ createFullSelector = createWithFiatActivity({ createActivitySelector: createFullSelector })
16
+ createFullSelector = createWithConnectionsActivity({
17
+ createActivitySelector: createFullSelector,
18
+ })
19
+
20
+ return createFullSelector
21
+ }
22
+
23
+ const createFullActivitySelectorDefinition = {
24
+ id: 'createFullActivity',
25
+ selectorFactory,
26
+ dependencies: [
27
+ { selector: 'createAssetSourceBaseActivity' },
28
+ { selector: 'createWithFiatActivity' },
29
+ { selector: 'createWithNftsActivity' },
30
+ { selector: 'createWithConnectionsActivity' },
31
+ ],
32
+ }
33
+
34
+ export default createFullActivitySelectorDefinition
@@ -0,0 +1,63 @@
1
+ import { memoize } from '@exodus/basic-utils'
2
+ import { createSelector } from 'reselect'
3
+ import assert from 'minimalistic-assert'
4
+ import { uniqBy } from 'lodash'
5
+
6
+ const selectorFactory =
7
+ () =>
8
+ ({ createAssetSourceActivitySelector, dedupExchange = true }) => {
9
+ assert(
10
+ createAssetSourceActivitySelector,
11
+ 'please provide createAssetSourceActivitySelector selector factory'
12
+ )
13
+
14
+ return memoize(
15
+ ({ assetNames, walletAccounts, ...rest }) => {
16
+ const selectors = []
17
+ for (const assetName of assetNames) {
18
+ for (const walletAccount of walletAccounts) {
19
+ selectors.push(
20
+ createAssetSourceActivitySelector({
21
+ assetName,
22
+ walletAccount,
23
+ ...rest,
24
+ })
25
+ )
26
+ }
27
+ }
28
+
29
+ return createSelector(...selectors, (...activities) => {
30
+ const ordersIncluded = new Set()
31
+ let result = activities.flat()
32
+ if (dedupExchange) {
33
+ result = result.filter((activityItem) => {
34
+ const { orderId } = activityItem
35
+ if (orderId) {
36
+ if (!ordersIncluded.has(orderId)) {
37
+ ordersIncluded.add(orderId)
38
+ return true
39
+ }
40
+
41
+ return false
42
+ }
43
+
44
+ return true
45
+ })
46
+ }
47
+
48
+ result = uniqBy(result, 'id')
49
+ return result.sort((a, b) => (b.date === a.date ? 0 : b.date > a.date ? 1 : -1))
50
+ })
51
+ },
52
+ ({ assetNames, walletAccounts, ...rest }) =>
53
+ `${assetNames.join(',')}_${walletAccounts.join(',')}_${JSON.stringify(rest)}`
54
+ )
55
+ }
56
+
57
+ const createMultiActivitySelectorDefinition = {
58
+ id: 'createMultiActivity',
59
+ selectorFactory,
60
+ dependencies: [],
61
+ }
62
+
63
+ export default createMultiActivitySelectorDefinition
@@ -0,0 +1,54 @@
1
+ import { memoize } from '@exodus/basic-utils'
2
+ import { createSelector } from 'reselect'
3
+ import assert from 'minimalistic-assert'
4
+
5
+ const selectorFactory =
6
+ (getConnectedOriginsSelector) =>
7
+ ({ createActivitySelector }) => {
8
+ assert(createActivitySelector, 'please provide activitySelector')
9
+
10
+ return memoize(
11
+ ({ assetName, walletAccount, ...rest }) => {
12
+ const activitySelector = createActivitySelector({ assetName, walletAccount, ...rest })
13
+ assert(activitySelector, 'createActivitySelector must return selector')
14
+ if (getConnectedOriginsSelector.isFallback) return activitySelector
15
+ return createSelector(
16
+ getConnectedOriginsSelector,
17
+ activitySelector,
18
+ (getConnectedOrigins, activity) => {
19
+ if (!getConnectedOrigins) return activity
20
+ let hasChanges = false
21
+
22
+ const resultActivity = []
23
+ for (const activityItem of activity) {
24
+ const personalNote = activityItem.personalNote
25
+ const origin = personalNote?.providerData?.origin
26
+ const connection = origin ? getConnectedOrigins(origin) : null
27
+ if (connection) {
28
+ hasChanges = true
29
+ resultActivity.push({
30
+ ...activityItem,
31
+ connection,
32
+ })
33
+ } else {
34
+ resultActivity.push(activityItem)
35
+ }
36
+ }
37
+
38
+ if (!hasChanges) return activity
39
+
40
+ return resultActivity
41
+ }
42
+ )
43
+ },
44
+ (deps) => JSON.stringify(deps)
45
+ )
46
+ }
47
+
48
+ const createWithConnectionsActivitySelectorDefinition = {
49
+ id: 'createWithConnectionsActivity',
50
+ selectorFactory,
51
+ dependencies: [{ module: 'connectedOrigins', selector: 'get', optional: true }],
52
+ }
53
+
54
+ export default createWithConnectionsActivitySelectorDefinition
@@ -0,0 +1,62 @@
1
+ import { memoize } from '@exodus/basic-utils'
2
+ import { createSelector } from 'reselect'
3
+ import assert from 'minimalistic-assert'
4
+ import { TX_TYPES } from '../constants/tx-types'
5
+
6
+ const selectorFactory =
7
+ (visibleOrdersSelector, assetsSelector) =>
8
+ ({ createActivitySelector }) => {
9
+ assert(createActivitySelector, 'please provide activitySelector')
10
+
11
+ return memoize(
12
+ ({ assetName, walletAccount, ...rest }) => {
13
+ const activitySelector = createActivitySelector({ assetName, walletAccount, ...rest })
14
+ assert(activitySelector, 'createActivitySelector must return selector')
15
+ if (visibleOrdersSelector.isFallback) return activitySelector
16
+ return createSelector(
17
+ visibleOrdersSelector,
18
+ assetsSelector,
19
+ activitySelector,
20
+ (fiatOrders, assets, activity) => {
21
+ if (!fiatOrders) {
22
+ return activity
23
+ }
24
+
25
+ let hasChanges = false
26
+
27
+ const resultActivity = []
28
+ for (const activityItem of activity) {
29
+ const fiatOrder = fiatOrders.getByTxId(activityItem.txId)
30
+
31
+ if (fiatOrder) {
32
+ hasChanges = true
33
+ resultActivity.push({
34
+ ...activityItem,
35
+ fiatOrder,
36
+ type: TX_TYPES.FIAT,
37
+ })
38
+ } else {
39
+ resultActivity.push(activityItem)
40
+ }
41
+ }
42
+
43
+ if (!hasChanges) return activity
44
+
45
+ return resultActivity
46
+ }
47
+ )
48
+ },
49
+ (deps) => JSON.stringify(deps)
50
+ )
51
+ }
52
+
53
+ const createWithFiatActivitySelectorDefinition = {
54
+ id: 'createWithFiatActivity',
55
+ selectorFactory,
56
+ dependencies: [
57
+ { module: 'fiatRamp', selector: 'visibleOrders', optional: true },
58
+ { module: 'assets', selector: 'all' },
59
+ ],
60
+ }
61
+
62
+ export default createWithFiatActivitySelectorDefinition
@@ -0,0 +1,81 @@
1
+ import { memoize } from '@exodus/basic-utils'
2
+ import { createSelector } from 'reselect'
3
+ import { formatUnindexedNftTx } from '../utils/formatters'
4
+ import assert from 'minimalistic-assert'
5
+ import { TX_TYPES } from '../constants/tx-types'
6
+
7
+ const selectorFactory =
8
+ (createAssetSourceNftTxsById, assetsSelector) =>
9
+ ({ createActivitySelector, nftsNetworkNameToAssetName }) => {
10
+ assert(createActivitySelector, 'please provide activitySelector')
11
+ assert(nftsNetworkNameToAssetName, 'please provide nftsNetworkNameToAssetName')
12
+
13
+ return memoize(
14
+ ({ assetName, walletAccount, ...rest }) => {
15
+ const activitySelector = createActivitySelector({ assetName, walletAccount, ...rest })
16
+ if (createAssetSourceNftTxsById.isFallback) {
17
+ return activitySelector
18
+ }
19
+
20
+ const nftsSelector = createAssetSourceNftTxsById({ assetName, walletAccount })
21
+ assert(nftsSelector, 'nfts redux feature must be installed to use this selector')
22
+ return createSelector(
23
+ nftsSelector,
24
+ assetsSelector,
25
+ activitySelector,
26
+ (nftsByTxId, assets, activity) => {
27
+ const indexedNftTxIds = new Set()
28
+ const resultActivity = []
29
+ let hasChanges = false
30
+ for (const activityItem of activity) {
31
+ const nft = nftsByTxId.get(activityItem.txId)
32
+
33
+ if (nft) {
34
+ hasChanges = true
35
+ indexedNftTxIds.add(nft.txId)
36
+ resultActivity.push({
37
+ ...activityItem,
38
+ nft,
39
+ type: TX_TYPES.NFT,
40
+ sent: nft.sent === undefined ? activityItem.sent : nft.sent, // rely on nft metadata for nft txs
41
+ })
42
+ } else {
43
+ resultActivity.push(activityItem)
44
+ }
45
+ }
46
+
47
+ ;[...nftsByTxId.values()]
48
+ .filter(
49
+ (nftTx) =>
50
+ assetName === nftsNetworkNameToAssetName[nftTx.network] &&
51
+ !indexedNftTxIds.has(nftTx.txId)
52
+ )
53
+ .forEach((nftTx) => {
54
+ hasChanges = true
55
+ const assetName = nftsNetworkNameToAssetName[nftTx.network]
56
+ const asset = assets[assetName]
57
+ const formatted = formatUnindexedNftTx({ nftTx, asset })
58
+
59
+ resultActivity.push(formatted)
60
+ })
61
+
62
+ if (!hasChanges) return activity
63
+
64
+ return resultActivity
65
+ }
66
+ )
67
+ },
68
+ ({ assetName, walletAccount, ...rest }) => `${assetName}_${walletAccount}_${rest}`
69
+ )
70
+ }
71
+
72
+ const createWithNftsActivitySelectorDefinition = {
73
+ id: 'createWithNftsActivity',
74
+ selectorFactory,
75
+ dependencies: [
76
+ { module: 'nfts', selector: 'createAssetSourceNftTxsById', optional: true },
77
+ { module: 'assets', selector: 'all' },
78
+ ],
79
+ }
80
+
81
+ export default createWithNftsActivitySelectorDefinition
@@ -1,9 +1,21 @@
1
1
  import createLimitedAssetSourceSelectorDefinition from './create-limited-asset-source'
2
2
  import createBatchedAssetSourceSelector from './create-batched-asset-source'
3
3
  import createBatchedAssetSourceActivityByIdSelector from './create-batched-asset-source-by-id'
4
+ import createAssetSourceBaseActivitySelectorDefinition from './create-asset-source-base-activity'
5
+ import createWithNftsActivitySelectorDefinition from './create-with-nfts-activity'
6
+ import createWithFiatActivitySelectorDefinition from './create-with-fiat-activity'
7
+ import createWithConnectionsActivitySelectorDefinition from './create-with-connections-activity'
8
+ import createFullActivitySelectorDefinition from './create-full-activity'
9
+ import createMultiActivitySelectorDefinition from './create-multi-activity'
4
10
 
5
11
  export default [
6
12
  createLimitedAssetSourceSelectorDefinition,
7
13
  createBatchedAssetSourceSelector,
8
14
  createBatchedAssetSourceActivityByIdSelector,
15
+ createAssetSourceBaseActivitySelectorDefinition,
16
+ createWithNftsActivitySelectorDefinition,
17
+ createWithFiatActivitySelectorDefinition,
18
+ createWithConnectionsActivitySelectorDefinition,
19
+ createFullActivitySelectorDefinition,
20
+ createMultiActivitySelectorDefinition,
9
21
  ]
@@ -0,0 +1,107 @@
1
+ import { TX_TYPES } from '../constants/tx-types'
2
+
3
+ const FINAL_ORDER_STATUS = {
4
+ inProgress: 'in-progress',
5
+ failed: 'failed',
6
+ success: 'complete',
7
+ }
8
+
9
+ const EXODEX_TX_TYPES = {
10
+ PRE_SETUP: 'preSetupTransaction',
11
+ SETUP: 'setupTransaction',
12
+ SWAP: 'swapTransaction',
13
+ CLEANUP: 'cleanupTransaction',
14
+ }
15
+
16
+ const UI_TX_TYPE_FROM_EXODEX = {
17
+ [EXODEX_TX_TYPES.PRE_SETUP]: TX_TYPES.APPROVAL,
18
+ [EXODEX_TX_TYPES.SETUP]: TX_TYPES.APPROVAL,
19
+ [EXODEX_TX_TYPES.SWAP]: TX_TYPES.EXCHANGE,
20
+ [EXODEX_TX_TYPES.CLEANUP]: TX_TYPES.CLEANUP,
21
+ }
22
+
23
+ function getTxType({ tx, order }) {
24
+ if (order) {
25
+ const txInfoFromOrder = order.txIds?.find((txFromOrder) => txFromOrder.txId === tx.txId)
26
+ return UI_TX_TYPE_FROM_EXODEX[txInfoFromOrder?.txType] || TX_TYPES.EXCHANGE
27
+ }
28
+
29
+ return tx.sent ? TX_TYPES.SENT : TX_TYPES.RECEIVED
30
+ }
31
+
32
+ const getMinConfirmations = (asset) => asset.baseAsset.minConfirmations || 1
33
+
34
+ export function isPending(tx, asset) {
35
+ return (
36
+ tx.confirmations < getMinConfirmations(asset) &&
37
+ !tx.dropped && // dropped txs are not pending anymore
38
+ !tx.error // errored txs are not pending anymore
39
+ )
40
+ }
41
+
42
+ const formatBase = ({ tx, asset, order, personalNote }) => ({
43
+ ...tx,
44
+ assetName: asset.name,
45
+ displayTicker: asset.displayTicker,
46
+ type: getTxType({ tx, asset, order }),
47
+ time: tx.date,
48
+ amount: tx.coinAmount.abs().toDefaultNumber(),
49
+ pending: isPending(tx, asset),
50
+ isOrderInProgress: !!order && order.exodusStatus === FINAL_ORDER_STATUS.inProgress,
51
+ confirmations: tx.confirmations,
52
+ failed: tx.failed,
53
+ received: tx.received,
54
+ personalNote,
55
+ })
56
+
57
+ export const formatGroupedExchangeTxs = ({ tx, assets, order, personalNote }) => {
58
+ const toAsset = assets[order.toAsset]
59
+
60
+ return {
61
+ ...formatBase({ tx, asset: toAsset, order, personalNote }),
62
+ failed: tx.failed || order.error,
63
+ pending: order.exodusStatus === FINAL_ORDER_STATUS.inProgress,
64
+ assetName: toAsset.name,
65
+ txId: tx.txId,
66
+ type: TX_TYPES.EXCHANGE,
67
+ time: tx.date,
68
+ fromAsset: order.fromAsset,
69
+ toAsset: order.toAsset,
70
+ amount: order.toAmount,
71
+ orderId: order.orderId,
72
+ data: {
73
+ swapTx: true,
74
+ },
75
+ }
76
+ }
77
+
78
+ const formatGroupedTx = ({ tx, assets, personalNote }) =>
79
+ formatBase({
80
+ tx,
81
+ asset: assets[tx.coinName],
82
+ personalNote,
83
+ })
84
+
85
+ export const formattersByType = {
86
+ exchange: formatGroupedExchangeTxs,
87
+ tx: formatGroupedTx,
88
+ }
89
+
90
+ export const formatUnindexedNftTx = ({ asset, nftTx }) => {
91
+ return {
92
+ id: `${asset.name}.${nftTx.txId}`,
93
+ coinName: asset.name,
94
+ assetName: asset.name,
95
+ displayTicker: asset.displayTicker,
96
+ type: TX_TYPES.NFT,
97
+ time: new Date(nftTx.date),
98
+ from: nftTx.from,
99
+ to: nftTx.to,
100
+ sent: Boolean(nftTx.sent),
101
+ received: !nftTx.sent,
102
+ date: new Date(nftTx.date),
103
+ nft: nftTx,
104
+ txId: nftTx.txId,
105
+ selfSend: false,
106
+ }
107
+ }