@exodus/activity-txs 5.0.2 → 6.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/CHANGELOG.md CHANGED
@@ -3,6 +3,34 @@
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
+ ## [6.0.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/activity-txs@5.0.2...@exodus/activity-txs@6.0.0) (2026-01-26)
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ - **orders:** use typescript (#14786)
11
+
12
+ ### Features
13
+
14
+ - feat: update all consumers to use safe strings for error namespaces (#14429)
15
+
16
+ ### Bug Fixes
17
+
18
+ - fix(activity-txs): fiat order duplicates wallet order (#14959)
19
+
20
+ - fix: update NFT transaction sent status calculation (#14359)
21
+
22
+ - refactor(orders)!: use typescript (#14786)
23
+
24
+ ## [5.1.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/activity-txs@5.0.2...@exodus/activity-txs@5.1.0) (2025-11-19)
25
+
26
+ ### Features
27
+
28
+ - feat: update all consumers to use safe strings for error namespaces (#14429)
29
+
30
+ ### Bug Fixes
31
+
32
+ - fix: update NFT transaction sent status calculation (#14359)
33
+
6
34
  ## [5.0.2](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/activity-txs@5.0.1...@exodus/activity-txs@5.0.2) (2025-11-05)
7
35
 
8
36
  ### Bug Fixes
package/README.md CHANGED
@@ -4,7 +4,7 @@ This feature generates user-friendly activity from transactions, orders, fiat or
4
4
 
5
5
  ## How it works
6
6
 
7
- Each asset’s activity consists of a set of transactions transformed using `asset.api.getActivityTxs`, which returns an array of Tx [models](https://github.com/ExodusMovement/exodus-core/blob/cdff25bb962b2301613588c615c5ac09b05f260a/packages/models/src/tx/index.js#L10): `[Tx, Tx, Tx]`.
7
+ Each asset’s activity consists of a set of transactions transformed using `asset.api.getActivityTxs`, which returns an array of Tx [models](https://github.com/ExodusOSS/hydra/blob/7743f4ffcbdb0605deb4943a90ef2e718776c3bf/libraries/models/src/tx/index.ts#L60): `[Tx, Tx, Tx]`.
8
8
 
9
9
  **Most assets don't have this API and simply return the original transactions.**
10
10
 
@@ -147,7 +147,10 @@ const createActivityTxsAtom = ({
147
147
 
148
148
  return [assetName, activityTxs]
149
149
  } catch (e) {
150
- errorTracking.track({ error: e, namespace: 'activityTxs', context: { assetName } })
150
+ errorTracking.track({
151
+ error: e,
152
+ context: { assetName },
153
+ })
151
154
  logger.warn(`failed to get activity txs for asset: ${assetName}`, e)
152
155
  return [assetName, []]
153
156
  }
package/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { activityTxsAtomDefinition } from './atoms/index.js'
2
2
  import activityTxsPluginDefinition from './plugin/index.js'
3
+ import { safeString } from '@exodus/safe-string'
3
4
 
4
5
  const activityTxs = () => ({
5
- id: 'activityTxs',
6
+ id: safeString`activityTxs`,
6
7
  definitions: [
7
8
  {
8
9
  definition: activityTxsAtomDefinition,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/activity-txs",
3
- "version": "5.0.2",
3
+ "version": "6.0.0",
4
4
  "description": "The activity-txs feature",
5
5
  "author": "Exodus Movement, Inc.",
6
6
  "repository": {
@@ -37,6 +37,7 @@
37
37
  "@exodus/core-selectors": "^4.0.0",
38
38
  "@exodus/models": "^12.0.1",
39
39
  "@exodus/multi-account-redux": "^2.0.1",
40
+ "@exodus/safe-string": "^1.3.0",
40
41
  "@exodus/typeforce": "^1.19.0",
41
42
  "lodash": "^4.17.21",
42
43
  "minimalistic-assert": "^1.0.1",
@@ -45,15 +46,15 @@
45
46
  "devDependencies": {
46
47
  "@exodus/assets": "^11.0.0",
47
48
  "@exodus/assets-base": "^10.0.0",
48
- "@exodus/assets-feature": "^8.7.1",
49
- "@exodus/available-assets": "^8.8.0",
49
+ "@exodus/assets-feature": "^8.8.0",
50
+ "@exodus/available-assets": "^8.10.1",
50
51
  "@exodus/bitcoin-plugin": "^1.4.2",
51
52
  "@exodus/connected-origins": "^4.3.0",
52
- "@exodus/error-tracking": "^3.2.0",
53
- "@exodus/fiat-ramp": "^15.5.0",
53
+ "@exodus/error-tracking": "^3.3.0",
54
+ "@exodus/fiat-ramp": "^15.10.0",
54
55
  "@exodus/logger": "^1.2.3",
55
- "@exodus/nfts": "^9.6.1",
56
- "@exodus/orders": "^5.5.2",
56
+ "@exodus/nfts": "^9.6.2",
57
+ "@exodus/orders": "^6.0.1",
57
58
  "@exodus/personal-notes": "^3.9.0",
58
59
  "@exodus/redux-dependency-injection": "^4.1.2",
59
60
  "@exodus/wallet-accounts": "^20.2.1",
@@ -64,5 +65,5 @@
64
65
  "access": "public",
65
66
  "provenance": false
66
67
  },
67
- "gitHead": "e327423c6bddd97049003f3a2d31af9ba7aedc44"
68
+ "gitHead": "d818fc93bdc6d714f1fbbdcef90b5f1cc21680e2"
68
69
  }
@@ -2,7 +2,7 @@ import { memoize } from '@exodus/basic-utils'
2
2
  import { createSelector } from 'reselect'
3
3
  import assert from 'minimalistic-assert'
4
4
  import { TX_TYPES } from '../constants/tx-types.js'
5
- import { ORDER_STATUS } from '@exodus/models/lib/fiat-order/constants.js'
5
+ import { ORDER_STATUS, ORDER_TYPES } from '@exodus/models/lib/fiat-order/constants.js'
6
6
 
7
7
  const selectorFactory =
8
8
  (visibleOrdersSelector, assetsSelector) =>
@@ -24,8 +24,29 @@ const selectorFactory =
24
24
  }
25
25
 
26
26
  let hasChanges = false
27
+ const pendingFiatOrdersWithoutTx = []
28
+ const fiatOrdersWithoutTx = []
29
+
30
+ if (displayFiatOrdersWithoutTx) {
31
+ for (const order of fiatOrders) {
32
+ if (order.txId) continue
33
+
34
+ const isRelatedBuyOrder =
35
+ order.toWalletAccount === walletAccount && order.toAsset === assetName
36
+ const isRelatedSellOrder =
37
+ order.fromWalletAccount === walletAccount && order.fromAsset === assetName
38
+
39
+ if (isRelatedBuyOrder || isRelatedSellOrder) {
40
+ fiatOrdersWithoutTx.push(order)
41
+ if (order.exodusStatus === ORDER_STATUS.in_progress) {
42
+ pendingFiatOrdersWithoutTx.push(order)
43
+ }
44
+ }
45
+ }
46
+ }
27
47
 
28
48
  const resultActivity = []
49
+
29
50
  for (const activityItem of activity) {
30
51
  const fiatOrdersByTx = fiatOrders.getAllByTxId(activityItem.txId)
31
52
 
@@ -41,34 +62,38 @@ const selectorFactory =
41
62
  })
42
63
  }
43
64
  } else {
44
- resultActivity.push(activityItem)
45
- }
46
- }
65
+ if (activityItem.pending && pendingFiatOrdersWithoutTx.length > 0) {
66
+ const matchingOrderIndex = pendingFiatOrdersWithoutTx.findIndex((order) => {
67
+ const orderAmount =
68
+ order.orderType === ORDER_TYPES.sell ? order.fromAmount : order.toAmount
47
69
 
48
- if (displayFiatOrdersWithoutTx) {
49
- for (const fiatOrder of fiatOrders) {
50
- const isOrderWithoutTx = !fiatOrder.txId
51
- const isRelatedBuyOrder =
52
- fiatOrder.toWalletAccount === walletAccount && fiatOrder.toAsset === assetName
53
- const isRelatedSellOrder =
54
- fiatOrder.fromWalletAccount === walletAccount && fiatOrder.fromAsset === assetName
55
-
56
- if (isOrderWithoutTx && (isRelatedBuyOrder || isRelatedSellOrder)) {
57
- hasChanges = true
58
- const activityItem = {
59
- id: `${assetName}.fiat-order-without-tx.${fiatOrder.orderId}`,
60
- assetName,
61
- walletAccount,
62
- fiatOrder,
63
- type: TX_TYPES.FIAT,
64
- pending: fiatOrder.exodusStatus === ORDER_STATUS.in_progress,
65
- date: fiatOrder.date || new Date(),
70
+ return activityItem.tx?.coinAmount?.abs().equals(orderAmount)
71
+ })
72
+
73
+ if (matchingOrderIndex !== -1) {
74
+ hasChanges = true
75
+ pendingFiatOrdersWithoutTx.splice(matchingOrderIndex, 1)
76
+ continue
66
77
  }
67
- resultActivity.push(activityItem)
68
78
  }
79
+
80
+ resultActivity.push(activityItem)
69
81
  }
70
82
  }
71
83
 
84
+ for (const fiatOrder of fiatOrdersWithoutTx) {
85
+ hasChanges = true
86
+ resultActivity.push({
87
+ id: `${assetName}.fiat-order-without-tx.${fiatOrder.orderId}`,
88
+ assetName,
89
+ walletAccount,
90
+ fiatOrder,
91
+ type: TX_TYPES.FIAT,
92
+ pending: fiatOrder.exodusStatus === ORDER_STATUS.in_progress,
93
+ date: fiatOrder.date || new Date(),
94
+ })
95
+ }
96
+
72
97
  if (!hasChanges) return activity
73
98
 
74
99
  return resultActivity
@@ -1,8 +1,28 @@
1
- import { getSharedProps } from './get-shared-props.js'
2
1
  import { TX_TYPES } from '../../constants/tx-types.js'
3
2
  import { isPending } from './format-tx-activity.js'
3
+ import { getSharedProps } from './get-shared-props.js'
4
+
5
+ const determineNftSent = (nft, tx) => {
6
+ if (tx) {
7
+ if (tx.received !== undefined) {
8
+ return !tx.received
9
+ }
10
+
11
+ if (tx.coinAmount) {
12
+ return !tx.coinAmount.isPositive
13
+ }
14
+ }
15
+
16
+ if (nft.sent !== undefined) {
17
+ return nft.sent
18
+ }
19
+
20
+ return false
21
+ }
4
22
 
5
23
  export const formatUnindexedNftTx = ({ assetName, nftTx }) => {
24
+ const sent = nftTx.sent === undefined ? false : nftTx.sent
25
+
6
26
  return {
7
27
  ...getSharedProps({
8
28
  txId: nftTx.txId,
@@ -12,14 +32,16 @@ export const formatUnindexedNftTx = ({ assetName, nftTx }) => {
12
32
  id: `nft.${assetName}.${nftTx.txId}`,
13
33
  pending: false,
14
34
  failed: false,
15
- sent: nftTx.sent || false,
16
- received: !nftTx.sent,
35
+ sent,
36
+ received: !sent,
17
37
  }),
18
38
  nft: nftTx,
19
39
  }
20
40
  }
21
41
 
22
42
  export const formatNftTx = ({ tx, nft, assetName, asset, ...rest }) => {
43
+ const sent = determineNftSent(nft, tx)
44
+
23
45
  return {
24
46
  ...rest,
25
47
  ...getSharedProps({
@@ -30,8 +52,8 @@ export const formatNftTx = ({ tx, nft, assetName, asset, ...rest }) => {
30
52
  id: `nft.${assetName}.${tx.txId}`,
31
53
  pending: isPending(tx, asset),
32
54
  failed: !!tx.failed,
33
- sent: nft.sent || false,
34
- received: !nft.sent,
55
+ sent,
56
+ received: !sent,
35
57
  }),
36
58
  nft,
37
59
  tx,