@exodus/activity-txs 6.1.4 → 6.1.6

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,18 @@
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.1.6](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/activity-txs@6.1.5...@exodus/activity-txs@6.1.6) (2026-06-27)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **activity-txs:** handle iterable (TxSet) tx source in groupTxsWithSameOrder ([#17380](https://github.com/ExodusMovement/exodus-hydra/issues/17380)) ([9ad4b9f](https://github.com/ExodusMovement/exodus-hydra/commit/9ad4b9f3ffc9f01708498ebf1286c932b0b7a999))
11
+
12
+ ## [6.1.5](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/activity-txs@6.1.4...@exodus/activity-txs@6.1.5) (2026-06-25)
13
+
14
+ ### Bug Fixes
15
+
16
+ - **activity-txs:** suppress orphaned chained-swap bridge leg ([#17354](https://github.com/ExodusMovement/exodus-hydra/issues/17354)) ([328b41a](https://github.com/ExodusMovement/exodus-hydra/commit/328b41af15695bf4e4c3057360354fa7b7897d04))
17
+
6
18
  ## [6.1.4](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/activity-txs@6.1.3...@exodus/activity-txs@6.1.4) (2026-06-24)
7
19
 
8
20
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/activity-txs",
3
- "version": "6.1.4",
3
+ "version": "6.1.6",
4
4
  "description": "The activity-txs feature",
5
5
  "author": "Exodus Movement, Inc.",
6
6
  "repository": {
@@ -47,7 +47,7 @@
47
47
  "devDependencies": {
48
48
  "@exodus/assets": "^11.0.0",
49
49
  "@exodus/assets-base": "^12.0.0",
50
- "@exodus/assets-feature": "^9.2.3",
50
+ "@exodus/assets-feature": "^9.2.4",
51
51
  "@exodus/available-assets": "^8.11.0",
52
52
  "@exodus/bitcoin-plugin": "^2.0.0",
53
53
  "@exodus/connected-origins": "^4.3.0",
@@ -58,7 +58,7 @@
58
58
  "@exodus/orders": "^6.2.2",
59
59
  "@exodus/personal-notes": "^3.9.0",
60
60
  "@exodus/redux-dependency-injection": "^5.0.0",
61
- "@exodus/wallet-accounts": "^20.4.7",
61
+ "@exodus/wallet-accounts": "^20.4.8",
62
62
  "@types/minimalistic-assert": "^1.0.1",
63
63
  "redux": "^4.2.1"
64
64
  },
@@ -66,5 +66,5 @@
66
66
  "access": "public",
67
67
  "provenance": false
68
68
  },
69
- "gitHead": "18b49ce03aa47d805068bce4b76bf834be314747"
69
+ "gitHead": "1599b3ac77f23228ee4c61c1b131664fe1ff541c"
70
70
  }
@@ -55,20 +55,51 @@ const classifyTx = ({ tx, orderSet }) => {
55
55
  return isValidTx ? { type: 'exchange', order: foundOrder } : { type: 'tx' }
56
56
  }
57
57
 
58
+ const bridgeAmountKey = (tx) =>
59
+ tx.coinAmount ? `${tx.coinName}:${tx.coinAmount.abs().toBaseString()}` : undefined
60
+
61
+ const amountSign = (tx) => (tx.coinAmount.toBaseString().startsWith('-') ? -1 : 1)
62
+
58
63
  const groupTxsWithSameOrder = ({ txs, orderSet, isIndexless }) => {
59
- if (!orderSet) return txs.map((tx) => ({ tx, type: 'tx' }))
64
+ const txList = Array.isArray(txs) ? txs : [...txs]
65
+ if (!orderSet) return txList.map((tx) => ({ tx, type: 'tx' }))
66
+
67
+ const classifiedTxs = txList.map((tx) => ({ tx, ...classifyTx({ tx, orderSet }) }))
68
+
69
+ const orphanCounterparts = []
70
+ for (const { tx, type } of classifiedTxs) {
71
+ if (type !== 'suppress' || !tx.coinAmount) continue
72
+ const order = orderSet.getByTxId(tx.txId)
73
+ if (!order || order.fromTxId !== order.toTxId) continue
74
+ const key = bridgeAmountKey(tx)
75
+ if (key) orphanCounterparts.push({ key, sign: amountSign(tx), used: false })
76
+ }
77
+
78
+ const isOrphanedBridgeLeg = (tx) => {
79
+ if (orphanCounterparts.length === 0 || !tx.coinAmount) return false
80
+ if (orderSet.getByTxId(tx.txId)) return false
81
+ const key = bridgeAmountKey(tx)
82
+ if (!key) return false
83
+ const sign = amountSign(tx)
84
+ const match = orphanCounterparts.find((c) => !c.used && c.key === key && c.sign === -sign)
85
+ if (!match) return false
86
+ match.used = true
87
+ return true
88
+ }
60
89
 
61
90
  const exchangeByOrderId = new Map()
62
91
  const result = []
63
92
 
64
- for (const tx of txs) {
65
- const { type, order } = classifyTx({ tx, orderSet })
66
-
93
+ for (const { tx, type, order } of classifiedTxs) {
67
94
  if (type === 'suppress') {
68
95
  // Bridge leg of a chained swap, intentionally omitted from activity.
69
96
  continue
70
97
  }
71
98
 
99
+ if (type === 'tx' && isOrphanedBridgeLeg(tx)) {
100
+ continue
101
+ }
102
+
72
103
  if (isIndexless && order) {
73
104
  // Orders are the source of truth for indexless swaps.
74
105
  // Skip this tx and add it later as exchanged.