@exodus/ethereum-api 8.65.0 → 8.66.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,24 @@
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
+ ## [8.66.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.64.5...@exodus/ethereum-api@8.66.0) (2026-03-04)
7
+
8
+
9
+ ### Features
10
+
11
+
12
+ * feat: add USDT blacklist status APIs for ETH and TRX and expose TRX raw account (#7444)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+
18
+ * fix: avoid race conditions resulting in a `tipGasPrice` of `0` where possible (#7458)
19
+
20
+ * fix: harden EthlikeError and improve error handling in tx-send (#7308)
21
+
22
+
23
+
6
24
  ## [8.65.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.64.5...@exodus/ethereum-api@8.65.0) (2026-03-03)
7
25
 
8
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/ethereum-api",
3
- "version": "8.65.0",
3
+ "version": "8.66.0",
4
4
  "description": "Transaction monitors, fee monitors, RPC with the blockchain node, and other networking code for Ethereum and EVM-based blockchains",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@exodus/asset": "^2.0.4",
26
- "@exodus/asset-lib": "^5.3.0",
26
+ "@exodus/asset-lib": "^5.8.0",
27
27
  "@exodus/assets": "^11.4.0",
28
28
  "@exodus/basic-utils": "^3.0.1",
29
29
  "@exodus/bip44-constants": "^195.0.0",
@@ -33,6 +33,7 @@
33
33
  "@exodus/ethereum-meta": "^2.9.1",
34
34
  "@exodus/ethereumholesky-meta": "^2.0.5",
35
35
  "@exodus/ethereumjs": "^1.8.0",
36
+ "@exodus/ethersproject-abi": "^5.4.2-exodus.2",
36
37
  "@exodus/fetch": "^1.3.0",
37
38
  "@exodus/models": "^12.13.0",
38
39
  "@exodus/safe-string": "^1.4.0",
@@ -68,5 +69,5 @@
68
69
  "type": "git",
69
70
  "url": "git+https://github.com/ExodusMovement/assets.git"
70
71
  },
71
- "gitHead": "98c4dc4e2cd52781dadc2af4fae2b80ecc276626"
72
+ "gitHead": "c715aabef7146610ab562c184a971c675f6d088f"
72
73
  }
@@ -1,13 +1,17 @@
1
+ import { BlacklistCheckTypes } from '@exodus/asset-lib'
2
+ import { defaultAbiCoder } from '@exodus/ethersproject-abi'
3
+ import { safeString } from '@exodus/safe-string'
1
4
  import assert from 'minimalistic-assert'
2
5
  import ms from 'ms'
3
6
 
7
+ import { EVM_ERROR_REASONS, withErrorReason } from './error-wrapper.js'
4
8
  import { createEvmServer, createWsGateway, ValidMonitorTypes } from './exodus-eth-server/index.js'
5
9
  import { createEthereumHooks } from './hooks/index.js'
6
10
  import { ClarityMonitor } from './tx-log/clarity-monitor.js'
7
11
  import { ClarityMonitorV2 } from './tx-log/clarity-monitor-v2.js'
8
12
  import { EthereumMonitor } from './tx-log/ethereum-monitor.js'
9
13
  import { EthereumNoHistoryMonitor } from './tx-log/ethereum-no-history-monitor.js'
10
- import { BLOCK_TAG_PENDING, resolveNonce } from './tx-send/nonce-utils.js'
14
+ import { BLOCK_TAG_LATEST, BLOCK_TAG_PENDING, resolveNonce } from './tx-send/nonce-utils.js'
11
15
 
12
16
  // Determines the appropriate `monitorType`, `serverUrl` and `monitorInterval`
13
17
  // to use for a given config.
@@ -245,3 +249,64 @@ export const getNonceFactory = ({ assetClientInterface, useAbsoluteBalanceAndNon
245
249
 
246
250
  return { getNonce }
247
251
  }
252
+
253
+ // Creates a contract-based blacklist check function.
254
+ // async ({ address }) => boolean
255
+ export const createContractBlackListCheck = ({ contractAddress, selector, server }) => {
256
+ assert(contractAddress, 'expected contractAddress')
257
+ assert(selector, 'expected selector')
258
+ assert(server, 'expected server')
259
+
260
+ return async ({ address }) => {
261
+ const tag = BLOCK_TAG_LATEST
262
+ const encodedAddress = address.slice(2).toLowerCase().padStart(64, '0')
263
+ const data = selector + encodedAddress
264
+ const result = await withErrorReason({
265
+ promise: server.ethCall({ to: contractAddress, data }, tag),
266
+ errorReasonInfo: EVM_ERROR_REASONS.ethCallErc20Failed,
267
+ hint: safeString`getBlackListStatus:ethCall`,
268
+ baseAssetName: server.baseAssetName,
269
+ })
270
+
271
+ if (typeof result !== 'string' || result.length === 0) {
272
+ throw new Error('getBlackListStatus got invalid ethCall response')
273
+ }
274
+
275
+ let isBlacklisted
276
+ try {
277
+ ;[isBlacklisted] = defaultAbiCoder.decode(['bool'], result)
278
+ } catch (err) {
279
+ throw new Error(`getBlackListStatus got invalid ABI bool result: ${err.message}`)
280
+ }
281
+
282
+ return isBlacklisted
283
+ }
284
+ }
285
+
286
+ // Composes blacklist check factories into a single getBlackListStatus.
287
+ // Returns undefined if no checks are provided.
288
+ // Returns { isBlacklisted: true } if ANY check returns true.
289
+ // NOTE: blacklistChecks defaults to [] as a convenience, but it is the asset's responsibility
290
+ // to be properly configured with the appropriate checks. An empty array means no blacklist
291
+ // checks are run, which implies EIP-7702 is effectively enabled on that network with no whitelist.
292
+ export const createGetBlackListStatus = ({ address: addressApi, blacklistChecks = [], server }) => {
293
+ if (blacklistChecks.length === 0) return
294
+
295
+ assert(addressApi, 'expected address')
296
+
297
+ // Extend here to support additional blacklist sources (e.g. an internal database query).
298
+ const checks = blacklistChecks.map((factory) => {
299
+ if (factory.type === BlacklistCheckTypes.CONTRACT_CALL) {
300
+ assert(server, 'expected server for CONTRACT_CALL blacklist check')
301
+ return factory({ server })
302
+ }
303
+
304
+ throw new Error(`Unknown blacklist check type: ${factory.type}`)
305
+ })
306
+
307
+ return async ({ address }) => {
308
+ assert(addressApi.validate(address), 'getBlackListStatus requires a valid Ethereum address')
309
+ const results = await Promise.all(checks.map((check) => check({ address })))
310
+ return { isBlacklisted: results.some(Boolean) }
311
+ }
312
+ }
@@ -22,6 +22,7 @@ import assert from 'minimalistic-assert'
22
22
 
23
23
  import { addressHasHistoryFactory } from './address-has-history.js'
24
24
  import {
25
+ createGetBlackListStatus,
25
26
  createHistoryMonitorFactory,
26
27
  createTransactionPrivacyFactory,
27
28
  getNonceFactory,
@@ -68,6 +69,7 @@ export const createAssetFactory = ({
68
69
  useEip1191ChainIdChecksum = false,
69
70
  forceGasLimitEstimation = false,
70
71
  rpcBalanceAssetNames = [],
72
+ blacklistChecks = [],
71
73
  supportsCustomFees: defaultSupportsCustomFees = false,
72
74
  useAbsoluteBalanceAndNonce = false,
73
75
  delisted = false,
@@ -264,6 +266,8 @@ export const createAssetFactory = ({
264
266
 
265
267
  const { getNonce } = getNonceFactory({ assetClientInterface, useAbsoluteBalanceAndNonce })
266
268
 
269
+ const getBlackListStatus = createGetBlackListStatus({ server, address, blacklistChecks })
270
+
267
271
  const api = {
268
272
  addressHasHistory,
269
273
  broadcastTx: (...args) => server.sendRawTransaction(...args),
@@ -279,6 +283,7 @@ export const createAssetFactory = ({
279
283
  getActivityTxs,
280
284
  getBalances,
281
285
  getBalanceForAddress: createGetBalanceForAddress({ asset, server }),
286
+ ...(getBlackListStatus && { getBlackListStatus }),
282
287
  getConfirmationsNumber: () => confirmationsNumber,
283
288
  getDefaultAddressPath: () => defaultAddressPath,
284
289
  getFeeAsync: createTx, // createTx alias, remove me when possible
package/src/index.js CHANGED
@@ -100,6 +100,8 @@ export { txSendFactory } from './tx-send/index.js'
100
100
 
101
101
  export { createAssetFactory } from './create-asset.js'
102
102
 
103
+ export { createContractBlackListCheck } from './create-asset-utils.js'
104
+
103
105
  export {
104
106
  createAssetPluginFactory,
105
107
  fromAddEthereumChainParameterToFactoryParams,