@exodus/solana-api 3.27.1 → 3.27.3

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,26 @@
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
+ ## [3.27.3](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.27.2...@exodus/solana-api@3.27.3) (2026-01-13)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+
12
+ * fix: SOL clarity integration for txs (#7256)
13
+
14
+
15
+
16
+ ## [3.27.2](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.27.1...@exodus/solana-api@3.27.2) (2026-01-12)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+
22
+ * fix: check SOL token txs signers (#7247)
23
+
24
+
25
+
6
26
  ## [3.27.1](https://github.com/ExodusMovement/assets/compare/@exodus/solana-api@3.27.0...@exodus/solana-api@3.27.1) (2026-01-09)
7
27
 
8
28
  **Note:** Version bump only for package @exodus/solana-api
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/solana-api",
3
- "version": "3.27.1",
3
+ "version": "3.27.3",
4
4
  "description": "Transaction monitors, fee monitors, RPC with the blockchain node, and other networking code for Solana",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -49,7 +49,7 @@
49
49
  "@exodus/assets-testing": "^1.0.0",
50
50
  "@exodus/solana-web3.js": "^1.63.1-exodus.9-rc3"
51
51
  },
52
- "gitHead": "62748839770af085bedc9708a2d2ae5efa4ad84b",
52
+ "gitHead": "ecc849a8b24d0d0f5518437dc58d3fb943a2a1cd",
53
53
  "bugs": {
54
54
  "url": "https://github.com/ExodusMovement/assets/issues?q=is%3Aissue+is%3Aopen+label%3Asolana-api"
55
55
  },
package/src/api.js CHANGED
@@ -22,6 +22,7 @@ import urljoin from 'url-join'
22
22
 
23
23
  import { getStakeActivation } from './get-stake-activation/index.js'
24
24
  import { parseTransaction } from './tx-parser.js'
25
+ import { isSolAddressPoisoningTx } from './txs-utils.js'
25
26
 
26
27
  const createApi = createApiCJS.default || createApiCJS
27
28
 
@@ -232,12 +233,7 @@ export class Api {
232
233
  })
233
234
 
234
235
  if (!parsedTx.from && parsedTx.tokenTxs?.length === 0 && !includeUnparsed) return // cannot parse it
235
- if (
236
- !parsedTx.ownerIsFeePayer &&
237
- parsedTx.error &&
238
- parsedTx.from === address &&
239
- !parsedTx.signers.includes(address)
240
- ) {
236
+ if (isSolAddressPoisoningTx({ parsedTx, address })) {
241
237
  return
242
238
  } // skip address poisoning txs attempts.
243
239
 
@@ -18,7 +18,8 @@ const TX_STALE_AFTER = ms('2m') // mark txs as dropped after N minutes
18
18
 
19
19
  export class SolanaClarityMonitor extends BaseMonitor {
20
20
  constructor({
21
- api,
21
+ clarityApi,
22
+ rpcApi,
22
23
  includeUnparsed = false,
23
24
  ticksBetweenHistoryFetches = TICKS_BETWEEN_HISTORY_FETCHES,
24
25
  ticksBetweenStakeFetches = TICKS_BETWEEN_STAKE_FETCHES,
@@ -27,8 +28,9 @@ export class SolanaClarityMonitor extends BaseMonitor {
27
28
  ...args
28
29
  }) {
29
30
  super(args)
30
- assert(api, 'api is required')
31
- this.api = api
31
+ assert(clarityApi, 'clarityApi is required')
32
+ this.clarityApi = clarityApi
33
+ this.rpcApi = rpcApi
32
34
  this.cursors = Object.create(null)
33
35
  this.assets = Object.create(null)
34
36
  this.staking = DEFAULT_REMOTE_CONFIG.staking
@@ -45,8 +47,8 @@ export class SolanaClarityMonitor extends BaseMonitor {
45
47
  clarityUrl,
46
48
  staking = Object.create(null),
47
49
  } = { ...DEFAULT_REMOTE_CONFIG, ...config }
48
- this.api.setRpcServer(rpcUrl[0])
49
- this.api.setClarityServer(clarityUrl[0])
50
+ this.clarityApi.setRpcServer(rpcUrl[0])
51
+ this.clarityApi.setClarityServer(clarityUrl[0])
50
52
  this.staking = staking
51
53
  }
52
54
 
@@ -56,9 +58,9 @@ export class SolanaClarityMonitor extends BaseMonitor {
56
58
  }
57
59
 
58
60
  async emitUnknownTokensEvent({ tokenAccounts }) {
59
- const tokensList = await this.api.getWalletTokensList({ tokenAccounts })
61
+ const tokensList = await this.clarityApi.getWalletTokensList({ tokenAccounts })
60
62
  const unknownTokensList = tokensList.filter((mintAddress) => {
61
- return !this.api.tokens.has(mintAddress)
63
+ return !this.clarityApi.tokens.has(mintAddress)
62
64
  })
63
65
  if (unknownTokensList.length > 0) {
64
66
  this.emit('unknown-tokens', unknownTokensList)
@@ -112,7 +114,7 @@ export class SolanaClarityMonitor extends BaseMonitor {
112
114
  async tick({ walletAccount, refresh }) {
113
115
  const assetName = this.asset.name
114
116
  this.assets = await this.aci.getAssetsForNetwork({ baseAssetName: assetName })
115
- this.api.setTokens(this.assets)
117
+ this.clarityApi.setTokens(this.assets)
116
118
 
117
119
  const accountState = await this.aci.getAccountState({ assetName, walletAccount })
118
120
  const address = await this.aci.getReceiveAddress({ assetName, walletAccount, useCache: true })
@@ -181,7 +183,9 @@ export class SolanaClarityMonitor extends BaseMonitor {
181
183
  const cursor = refresh ? '' : accountState.cursor
182
184
  const baseAsset = this.asset
183
185
 
184
- const { transactions, newCursor } = await this.api.getTransactions(address, {
186
+ // TODO: switch to this.clarityApi.getTransactions once ready!!
187
+ // and remove this.rpcApi from constructor and create-asset-utils.js
188
+ const { transactions, newCursor } = await this.rpcApi.getTransactions(address, {
185
189
  cursor,
186
190
  includeUnparsed: this.includeUnparsed,
187
191
  limit: this.txsLimit,
@@ -192,7 +196,7 @@ export class SolanaClarityMonitor extends BaseMonitor {
192
196
  for (const tx of transactions) {
193
197
  // we get the token name using the token.mintAddress
194
198
  const assetName = tx.token
195
- ? this.api.tokens.get(tx.token.mintAddress)?.name ?? 'unknown'
199
+ ? this.clarityApi.tokens.get(tx.token.mintAddress)?.name ?? 'unknown'
196
200
  : baseAsset.name
197
201
 
198
202
  const asset = this.assets[assetName]
@@ -267,8 +271,8 @@ export class SolanaClarityMonitor extends BaseMonitor {
267
271
 
268
272
  async getAccountsAndBalances({ refresh, address, accountState, walletAccount }) {
269
273
  const [accountInfo, { balances: splBalances, accounts: tokenAccounts }] = await Promise.all([
270
- this.api.getAccountInfo(address).catch(() => {}),
271
- this.api.getTokensBalancesAndAccounts({
274
+ this.clarityApi.getAccountInfo(address).catch(() => {}),
275
+ this.clarityApi.getTokensBalancesAndAccounts({
272
276
  address,
273
277
  }),
274
278
  ])
@@ -278,19 +282,19 @@ export class SolanaClarityMonitor extends BaseMonitor {
278
282
  const accountSize = accountInfo?.space || 0
279
283
 
280
284
  const rentExemptAmount = this.asset.currency.baseUnit(
281
- await this.api.getMinimumBalanceForRentExemption(accountSize)
285
+ await this.clarityApi.getMinimumBalanceForRentExemption(accountSize)
282
286
  )
283
287
 
284
- const ownerChanged = await this.api.ownerChanged(address, accountInfo)
288
+ const ownerChanged = await this.clarityApi.ownerChanged(address, accountInfo)
285
289
 
286
290
  // we can have splBalances for tokens that are not in our asset list
287
291
  const clientKnownTokens = omitBy(splBalances, (v, mintAddress) => {
288
- const tokenName = this.api.tokens.get(mintAddress)?.name
292
+ const tokenName = this.clarityApi.tokens.get(mintAddress)?.name
289
293
  return !this.assets[tokenName]
290
294
  })
291
295
  const tokenBalances = Object.fromEntries(
292
296
  Object.entries(clientKnownTokens).map(([mintAddress, balance]) => {
293
- const tokenName = this.api.tokens.get(mintAddress)?.name
297
+ const tokenName = this.clarityApi.tokens.get(mintAddress)?.name
294
298
  return [tokenName, this.assets[tokenName].currency.baseUnit(balance)]
295
299
  })
296
300
  )
@@ -352,10 +356,10 @@ export class SolanaClarityMonitor extends BaseMonitor {
352
356
  }
353
357
 
354
358
  async getStakingInfo({ address, accountState, walletAccount }) {
355
- const stakingInfo = await this.api.getStakeAccountsInfo(address)
359
+ const stakingInfo = await this.clarityApi.getStakeAccountsInfo(address)
356
360
  let earned = accountState.stakingInfo.earned.toBaseString()
357
361
  try {
358
- const rewards = await this.api.getRewards(address)
362
+ const rewards = await this.clarityApi.getRewards(address)
359
363
  earned = rewards
360
364
  } catch (error) {
361
365
  console.warn(error)
@@ -13,11 +13,10 @@ const DEFAULT_REMOTE_CONFIG = {
13
13
  const TICKS_BETWEEN_HISTORY_FETCHES = 10
14
14
  const TICKS_BETWEEN_STAKE_FETCHES = 5
15
15
  const TX_STALE_AFTER = ms('2m') // mark txs as dropped after N minutes
16
- const FORCE_HTTP = true // use https over ws
17
16
 
18
17
  export class SolanaMonitor extends BaseMonitor {
19
18
  constructor({
20
- api,
19
+ rpcApi,
21
20
  includeUnparsed = false,
22
21
  ticksBetweenHistoryFetches = TICKS_BETWEEN_HISTORY_FETCHES,
23
22
  ticksBetweenStakeFetches = TICKS_BETWEEN_STAKE_FETCHES,
@@ -26,8 +25,8 @@ export class SolanaMonitor extends BaseMonitor {
26
25
  ...args
27
26
  }) {
28
27
  super(args)
29
- assert(api, 'api is required')
30
- this.api = api
28
+ assert(rpcApi, 'rpcApi is required')
29
+ this.rpcApi = rpcApi
31
30
  this.cursors = {}
32
31
  this.assets = {}
33
32
  this.staking = DEFAULT_REMOTE_CONFIG.staking
@@ -36,52 +35,11 @@ export class SolanaMonitor extends BaseMonitor {
36
35
  this.shouldUpdateBalanceBeforeHistory = shouldUpdateBalanceBeforeHistory
37
36
  this.includeUnparsed = includeUnparsed
38
37
  this.txsLimit = txsLimit
39
- this.addHook('before-stop', (...args) => this.beforeStop(...args))
40
- }
41
-
42
- async beforeStop() {
43
- const walletAccounts = await this.aci.getWalletAccounts({ assetName: this.asset.name })
44
- return Promise.all(walletAccounts.map((walletAccount) => this.stopListener({ walletAccount })))
45
- }
46
-
47
- async initWalletAccount({ walletAccount }) {
48
- if (this.tickCount[walletAccount] === 0) {
49
- await this.startListener({ walletAccount })
50
- }
51
- }
52
-
53
- async startListener({ walletAccount }) {
54
- if (FORCE_HTTP) return null
55
-
56
- const address = await this.aci.getReceiveAddress({
57
- assetName: this.asset.name,
58
- walletAccount,
59
- useCache: true,
60
- })
61
-
62
- return this.api.watchAddress({
63
- address,
64
- onMessage: (json) => {
65
- // new SOL tx event, tick monitor with 15 sec delay (to avoid hitting delayed nodes)
66
- setTimeout(() => this.tick({ walletAccount }), 15_000)
67
- },
68
- })
69
- }
70
-
71
- async stopListener({ walletAccount }) {
72
- if (FORCE_HTTP) return null
73
-
74
- const address = await this.aci.getReceiveAddress({
75
- assetName: this.asset.name,
76
- walletAccount,
77
- useCache: true,
78
- })
79
- return this.api.unwatchAddress({ address })
80
38
  }
81
39
 
82
40
  setServer(config = {}) {
83
41
  const { rpcs, staking = {} } = { ...DEFAULT_REMOTE_CONFIG, ...config }
84
- this.api.setServer(rpcs[0])
42
+ this.rpcApi.setServer(rpcs[0])
85
43
  this.staking = staking
86
44
  }
87
45
 
@@ -91,9 +49,9 @@ export class SolanaMonitor extends BaseMonitor {
91
49
  }
92
50
 
93
51
  async emitUnknownTokensEvent({ tokenAccounts }) {
94
- const tokensList = await this.api.getWalletTokensList({ tokenAccounts })
52
+ const tokensList = await this.rpcApi.getWalletTokensList({ tokenAccounts })
95
53
  const unknownTokensList = tokensList.filter((mintAddress) => {
96
- return !this.api.tokens.has(mintAddress)
54
+ return !this.rpcApi.tokens.has(mintAddress)
97
55
  })
98
56
  if (unknownTokensList.length > 0) {
99
57
  this.emit('unknown-tokens', unknownTokensList)
@@ -127,7 +85,7 @@ export class SolanaMonitor extends BaseMonitor {
127
85
  async markStaleTransactions({ walletAccount, logItemsByAsset = Object.create(null) }) {
128
86
  // mark stale txs as dropped in logItemsByAsset
129
87
  const clearedLogItems = logItemsByAsset
130
- const tokenNames = [...this.api.tokens.values()].map(({ name }) => name)
88
+ const tokenNames = [...this.rpcApi.tokens.values()].map(({ name }) => name)
131
89
  const assets = [this.asset.name, ...tokenNames]
132
90
 
133
91
  for (const assetName of assets) {
@@ -146,12 +104,9 @@ export class SolanaMonitor extends BaseMonitor {
146
104
  }
147
105
 
148
106
  async tick({ walletAccount, refresh }) {
149
- // Check for new wallet account
150
- await this.initWalletAccount({ walletAccount })
151
-
152
107
  const assetName = this.asset.name
153
108
  this.assets = await this.aci.getAssetsForNetwork({ baseAssetName: assetName })
154
- this.api.setTokens(this.assets)
109
+ this.rpcApi.setTokens(this.assets)
155
110
 
156
111
  const accountState = await this.aci.getAccountState({ assetName, walletAccount })
157
112
  const address = await this.aci.getReceiveAddress({ assetName, walletAccount, useCache: true })
@@ -213,7 +168,7 @@ export class SolanaMonitor extends BaseMonitor {
213
168
  const cursor = refresh ? '' : accountState.cursor
214
169
  const baseAsset = this.asset
215
170
 
216
- const { transactions, newCursor } = await this.api.getTransactions(address, {
171
+ const { transactions, newCursor } = await this.rpcApi.getTransactions(address, {
217
172
  cursor,
218
173
  includeUnparsed: this.includeUnparsed,
219
174
  limit: this.txsLimit,
@@ -224,7 +179,7 @@ export class SolanaMonitor extends BaseMonitor {
224
179
  for (const tx of transactions) {
225
180
  // we get the token name using the token.mintAddress
226
181
  const assetName = tx.token
227
- ? this.api.tokens.get(tx.token.mintAddress)?.name ?? 'unknown'
182
+ ? this.rpcApi.tokens.get(tx.token.mintAddress)?.name ?? 'unknown'
228
183
  : baseAsset.name
229
184
 
230
185
  const asset = this.assets[assetName]
@@ -300,8 +255,8 @@ export class SolanaMonitor extends BaseMonitor {
300
255
  async getAccountsAndBalances({ refresh, address, accountState, walletAccount }) {
301
256
  const tokens = Object.keys(this.assets).filter((name) => name !== this.asset.name)
302
257
  const [accountInfo, { balances: splBalances, accounts: tokenAccounts }] = await Promise.all([
303
- this.api.getAccountInfo(address).catch(() => {}),
304
- this.api.getTokensBalancesAndAccounts({
258
+ this.rpcApi.getAccountInfo(address).catch(() => {}),
259
+ this.rpcApi.getTokensBalancesAndAccounts({
305
260
  address,
306
261
  filterByTokens: tokens,
307
262
  }),
@@ -312,10 +267,10 @@ export class SolanaMonitor extends BaseMonitor {
312
267
  const accountSize = accountInfo?.space || 0
313
268
 
314
269
  const rentExemptAmount = this.asset.currency.baseUnit(
315
- await this.api.getMinimumBalanceForRentExemption(accountSize)
270
+ await this.rpcApi.getMinimumBalanceForRentExemption(accountSize)
316
271
  )
317
272
 
318
- const ownerChanged = await this.api.ownerChanged(address, accountInfo)
273
+ const ownerChanged = await this.rpcApi.ownerChanged(address, accountInfo)
319
274
 
320
275
  const tokenBalances = _.mapValues(splBalances, (balance, name) =>
321
276
  this.assets[name].currency.baseUnit(balance)
@@ -378,10 +333,10 @@ export class SolanaMonitor extends BaseMonitor {
378
333
  }
379
334
 
380
335
  async getStakingInfo({ address, accountState, walletAccount }) {
381
- const stakingInfo = await this.api.getStakeAccountsInfo(address)
336
+ const stakingInfo = await this.rpcApi.getStakeAccountsInfo(address)
382
337
  let earned = accountState.stakingInfo.earned.toBaseString()
383
338
  try {
384
- const rewards = await this.api.getRewards(address)
339
+ const rewards = await this.rpcApi.getRewards(address)
385
340
  earned = rewards
386
341
  } catch (error) {
387
342
  console.warn(error)
@@ -25,7 +25,7 @@ export class SolanaWebsocketMonitor extends SolanaClarityMonitor {
25
25
 
26
26
  async beforeStart() {
27
27
  this.assets = await this.aci.getAssetsForNetwork({ baseAssetName: this.asset.name })
28
- this.api.setTokens(this.assets)
28
+ this.clarityApi.setTokens(this.assets)
29
29
 
30
30
  const walletAccounts = await this.aci.getWalletAccounts({ assetName: this.asset.name })
31
31
  await Promise.all(
@@ -49,7 +49,7 @@ export class SolanaWebsocketMonitor extends SolanaClarityMonitor {
49
49
  useCache: true,
50
50
  })
51
51
 
52
- const { accounts: tokenAccountsByOwner } = await this.api.getTokensBalancesAndAccounts({
52
+ const { accounts: tokenAccountsByOwner } = await this.clarityApi.getTokensBalancesAndAccounts({
53
53
  address,
54
54
  })
55
55
  this.tokenAccountsByOwner[walletAccount] = tokenAccountsByOwner
@@ -88,7 +88,7 @@ export class SolanaWebsocketMonitor extends SolanaClarityMonitor {
88
88
 
89
89
  const assetName = this.asset.name
90
90
  this.assets = await this.aci.getAssetsForNetwork({ baseAssetName: assetName })
91
- this.api.setTokens(this.assets)
91
+ this.clarityApi.setTokens(this.assets)
92
92
  const address = await this.aci.getReceiveAddress({
93
93
  assetName,
94
94
  walletAccount,
@@ -103,7 +103,7 @@ export class SolanaWebsocketMonitor extends SolanaClarityMonitor {
103
103
 
104
104
  // we call this periodically to detect new token accounts created (there's not a WS event for this in Helius yet, we need programSubscribe)
105
105
  const { accounts: tokenAccounts, balances: splBalances } =
106
- await this.api.getTokensBalancesAndAccounts({
106
+ await this.clarityApi.getTokensBalancesAndAccounts({
107
107
  address,
108
108
  })
109
109
  this.tokenAccountsByOwner[walletAccount] = tokenAccounts
@@ -114,7 +114,7 @@ export class SolanaWebsocketMonitor extends SolanaClarityMonitor {
114
114
 
115
115
  // subscribe to new tokenAccounts
116
116
  for (const mintAddress of unknownTokensList) {
117
- const tokenName = this.api.tokens.get(mintAddress)?.name
117
+ const tokenName = this.clarityApi.tokens.get(mintAddress)?.name
118
118
  if (!tokenName) {
119
119
  console.log(`Unknown token mint address: ${mintAddress}`)
120
120
  continue
@@ -171,7 +171,7 @@ export class SolanaWebsocketMonitor extends SolanaClarityMonitor {
171
171
  // update account state balance for SOL or Token
172
172
  if (tokenMintAddress) {
173
173
  // token balance changed
174
- const tokenName = this.api.tokens.get(tokenMintAddress)?.name
174
+ const tokenName = this.clarityApi.tokens.get(tokenMintAddress)?.name
175
175
  if (!tokenName) {
176
176
  console.log(`Unknown token mint address: ${tokenMintAddress}`)
177
177
  return
@@ -228,7 +228,7 @@ export class SolanaWebsocketMonitor extends SolanaClarityMonitor {
228
228
  // update tx-log with new txs and state with cursor
229
229
 
230
230
  // NB. if we receive a tx with a new "token", never received before,
231
- // this.api.tokens will be populated with new tokens only after we ran a monitor tick
231
+ // this.clarityApi.tokens will be populated with new tokens only after we ran a monitor tick
232
232
  // since the unknown-tokens event is captured and processed in other places.
233
233
  // hence what happens is we skip the txLog update for that new token.
234
234
 
@@ -237,7 +237,7 @@ export class SolanaWebsocketMonitor extends SolanaClarityMonitor {
237
237
  walletAccount,
238
238
  baseAsset: this.asset,
239
239
  assets: this.assets,
240
- tokens: this.api.tokens,
240
+ tokens: this.clarityApi.tokens,
241
241
  tokenAccountsByOwner,
242
242
  result: data.params.result, // raw tx
243
243
  })
@@ -301,7 +301,7 @@ export class SolanaWebsocketMonitor extends SolanaClarityMonitor {
301
301
  // because we NEED at a certain point to have an updated stakingInfo in the state to know what's the new solana stake account address.
302
302
  const stakingInfo = await this.getStakingInfo({ address, accountState, walletAccount })
303
303
  const balance = this.#computeTotalBalance({
304
- amount: this.asset.currency.baseUnit(await this.api.getBalance(address)), // we needed the delay otherwise will never be updated right away.
304
+ amount: this.asset.currency.baseUnit(await this.clarityApi.getBalance(address)), // we needed the delay otherwise will never be updated right away.
305
305
  address,
306
306
  stakingInfo,
307
307
  walletAccount,
package/src/txs-utils.js CHANGED
@@ -23,3 +23,12 @@ export const isSolTransferInstruction = ({ program, type }) =>
23
23
 
24
24
  export const isSplMintInstruction = ({ program, type }) =>
25
25
  program === 'spl-token' && MINT_INSTRUCTION_TYPES.has(type)
26
+
27
+ export const isSolAddressPoisoningTx = ({ parsedTx, address }) => {
28
+ return (
29
+ !parsedTx.ownerIsFeePayer &&
30
+ parsedTx.error &&
31
+ (parsedTx.from === address || parsedTx?.tokenTxs?.some((tx) => tx.from === address)) && // send tx
32
+ !parsedTx.signers.includes(address)
33
+ )
34
+ }
package/src/ws-api.js CHANGED
@@ -3,6 +3,7 @@ import lodash from 'lodash'
3
3
 
4
4
  import { Connection } from './connection.js'
5
5
  import { parseTransaction } from './tx-parser.js'
6
+ import { isSolAddressPoisoningTx } from './txs-utils.js'
6
7
 
7
8
  // Helius Advanced WebSocket
8
9
  const WS_ENDPOINT = 'wss://solana-helius-wss.a.exodus.io/ws' // pointing to: wss://atlas-mainnet.helius-rpc.com/?api-key=<API_KEY>
@@ -150,12 +151,7 @@ export class WsApi {
150
151
  const timestamp = Date.now() // the notification event has no blockTime
151
152
 
152
153
  if (!parsedTx.from && parsedTx.tokenTxs?.length === 0) return { logItemsByAsset: {} } // cannot parse it
153
- if (
154
- !parsedTx.ownerIsFeePayer &&
155
- parsedTx.error &&
156
- parsedTx.from === address &&
157
- !parsedTx.signers.includes(address)
158
- ) {
154
+ if (isSolAddressPoisoningTx({ parsedTx, address })) {
159
155
  return { logItemsByAsset: {} } // skip address poisoning txs attempts.
160
156
  }
161
157