@exodus/ethereum-api 8.41.0 → 8.42.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,16 @@
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.42.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.41.0...@exodus/ethereum-api@8.42.0) (2025-07-10)
7
+
8
+
9
+ ### Features
10
+
11
+
12
+ * feat: rig `getNonce` to evm asset api (#6047)
13
+
14
+
15
+
6
16
  ## [8.41.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.40.1...@exodus/ethereum-api@8.41.0) (2025-07-01)
7
17
 
8
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/ethereum-api",
3
- "version": "8.41.0",
3
+ "version": "8.42.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",
@@ -63,5 +63,5 @@
63
63
  "type": "git",
64
64
  "url": "git+https://github.com/ExodusMovement/assets.git"
65
65
  },
66
- "gitHead": "1077a752b60e0b25961613fd007596ab3368188e"
66
+ "gitHead": "6bd56e57bee720ffef602f57421eae67e42e190c"
67
67
  }
@@ -1,3 +1,6 @@
1
+ import { isNumberUnit } from '@exodus/currency'
2
+ import assert from 'minimalistic-assert'
3
+
1
4
  import { getServer } from '../exodus-eth-server/index.js'
2
5
  import { fetchGasLimit } from '../gas-estimation.js'
3
6
  import { ALLOWANCE_TX_TIMEOUT, APPROVAL_GAS_LIMIT, ZERO_ALLOWANCE_ASSETS } from './constants.js'
@@ -27,6 +30,52 @@ export async function isSpendingApprovalRequired({
27
30
  return tokenAmount.gt(allowance)
28
31
  }
29
32
 
33
+ export const buildApproveTx = async ({
34
+ spenderAddress,
35
+ asset,
36
+ feeData,
37
+ fromAddress,
38
+ approveAmount = asset.currency.ZERO,
39
+ gasLimit,
40
+ txInput,
41
+ }) => {
42
+ assert(asset, 'expected asset')
43
+ assert(feeData, 'expected feeData')
44
+ assert(isNumberUnit(approveAmount), 'expected approveAmount')
45
+ assert(typeof spenderAddress === 'string', 'expected spenderAddress')
46
+
47
+ const baseAsset = asset.baseAsset
48
+ const toAddress = asset.contract.address
49
+
50
+ if (!txInput) txInput = asset.contract.approve.build(spenderAddress, approveAmount.toBaseString())
51
+
52
+ if (!gasLimit)
53
+ gasLimit = await fetchGasLimit({
54
+ asset: baseAsset,
55
+ amount: baseAsset.currency.ZERO,
56
+ toAddress,
57
+ txInput,
58
+ feeData,
59
+ isContract: true,
60
+ fromAddress,
61
+ })
62
+
63
+ return {
64
+ asset: baseAsset.name,
65
+ receiver: {
66
+ address: toAddress,
67
+ amount: baseAsset.currency.ZERO,
68
+ },
69
+ txInput,
70
+ gasPrice: feeData.gasPrice,
71
+ tipGasPrice: feeData.tipGasPrice,
72
+ gasLimit,
73
+ silent: true,
74
+ fromAddress,
75
+ }
76
+ }
77
+
78
+ // @deprecated use buildApproveTx instead
30
79
  export const createApprove =
31
80
  ({ sendTx }) =>
32
81
  async ({
@@ -36,43 +85,23 @@ export const createApprove =
36
85
  fromAddress,
37
86
  approveAmount,
38
87
  gasLimit,
39
- txInput: preTxInput,
40
- ...rest
88
+ txInput,
89
+ ...extras
41
90
  }) => {
42
- const baseAsset = asset.baseAsset
43
- const txInput =
44
- preTxInput ?? asset.contract.approve.build(spenderAddress, approveAmount.toBaseString())
45
-
46
- const toAddress = asset.contract.address
47
- const gasLimitOptions = {
48
- asset: baseAsset,
49
- amount: baseAsset.currency.ZERO,
50
- toAddress,
51
- txInput,
91
+ const approveTx = await buildApproveTx({
92
+ spenderAddress,
93
+ asset,
52
94
  feeData,
53
- isContract: true,
54
95
  fromAddress,
55
- }
56
-
57
- gasLimit = gasLimit || (await fetchGasLimit(gasLimitOptions))
58
-
59
- const txData = await sendTx({
60
- asset: baseAsset.name,
61
- receiver: {
62
- address: toAddress,
63
- amount: baseAsset.currency.ZERO,
64
- },
65
- txInput,
66
- gasPrice: feeData.gasPrice,
96
+ approveAmount,
67
97
  gasLimit,
68
- silent: true,
69
- fromAddress,
70
- ...rest,
98
+ txInput,
71
99
  })
72
100
 
73
- if (!txData || !txData.txId) {
101
+ const txData = await sendTx({ ...extras, ...approveTx })
102
+
103
+ if (!txData || !txData.txId)
74
104
  throw new Error(`Failed to approve ${asset.displayTicker} - ${spenderAddress}`)
75
- }
76
105
 
77
106
  return txData
78
107
  }
@@ -6,6 +6,7 @@ import { createEthereumHooks } from './hooks/index.js'
6
6
  import { ClarityMonitor } from './tx-log/clarity-monitor.js'
7
7
  import { EthereumMonitor } from './tx-log/ethereum-monitor.js'
8
8
  import { EthereumNoHistoryMonitor } from './tx-log/ethereum-no-history-monitor.js'
9
+ import { resolveNonce } from './tx-send/nonce-utils.js'
9
10
 
10
11
  // Determines the appropriate `monitorType`, `serverUrl` and `monitorInterval`
11
12
  // to use for a given config.
@@ -151,3 +152,33 @@ export const createHistoryMonitorFactory = ({
151
152
  return monitor
152
153
  }
153
154
  }
155
+
156
+ export const getNonceFactory = ({ assetClientInterface, useAbsoluteBalanceAndNonce }) => {
157
+ assert(assetClientInterface, 'expected assetClientInterface')
158
+ assert(typeof useAbsoluteBalanceAndNonce === 'boolean', 'expected useAbsoluteBalanceAndNonce')
159
+
160
+ const getNonce = async ({ asset, fromAddress, walletAccount }) => {
161
+ assert(asset, 'expected asset')
162
+ assert(typeof fromAddress === 'string', 'expected fromAddress')
163
+ assert(walletAccount, 'expected walletAccount')
164
+
165
+ const txLog = await assetClientInterface.getTxLog({
166
+ assetName: asset.baseAsset.name,
167
+ walletAccount,
168
+ })
169
+
170
+ return resolveNonce({
171
+ asset,
172
+ fromAddress,
173
+ txLog,
174
+ // For assets where we'll fall back to querying the coin node, we
175
+ // search for pending transactions. For base assets with history,
176
+ // we'll fall back to the `TxLog` since this also has a knowledge
177
+ // of which transactions are currently in pending.
178
+ tag: 'pending',
179
+ useAbsoluteNonce: useAbsoluteBalanceAndNonce,
180
+ })
181
+ }
182
+
183
+ return { getNonce }
184
+ }
@@ -24,6 +24,7 @@ import { addressHasHistoryFactory } from './address-has-history.js'
24
24
  import {
25
25
  createHistoryMonitorFactory,
26
26
  createTransactionPrivacyFactory,
27
+ getNonceFactory,
27
28
  resolveMonitorSettings,
28
29
  } from './create-asset-utils.js'
29
30
  import { createTokenFactory } from './create-token-factory.js'
@@ -237,6 +238,8 @@ export const createAssetFactory = ({
237
238
  ? getL1GetFeeFactory({ asset, originalGetFee })
238
239
  : originalGetFee
239
240
 
241
+ const { getNonce } = getNonceFactory({ assetClientInterface, useAbsoluteBalanceAndNonce })
242
+
240
243
  const api = {
241
244
  addressHasHistory,
242
245
  broadcastTx: (...args) => server.sendRawTransaction(...args),
@@ -293,6 +296,7 @@ export const createAssetFactory = ({
293
296
  broadcastPrivateBundle,
294
297
  broadcastPrivateTx,
295
298
  forceGasLimitEstimation,
299
+ getNonce,
296
300
  privacyServer,
297
301
  server,
298
302
  ...(erc20FuelBuffer && { erc20FuelBuffer }),
package/src/index.js CHANGED
@@ -61,6 +61,7 @@ export {
61
61
  isZeroAllowanceAsset,
62
62
  getSpendingAllowance,
63
63
  isSpendingApprovalRequired,
64
+ buildApproveTx,
64
65
  createApprove,
65
66
  createApproveSpendingTokens,
66
67
  APPROVAL_GAS_LIMIT,
@@ -204,17 +204,7 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx, useAbsoluteBala
204
204
  const resolvedNonce =
205
205
  providedNonce ??
206
206
  bumpNonce ??
207
- (await resolveNonce({
208
- asset,
209
- fromAddress,
210
- txLog: baseAssetTxLog,
211
- // For assets where we'll fall back to querying the coin node, we
212
- // search for pending transactions. For base assets with history,
213
- // we'll fall back to the `TxLog` since this also has a knowledge
214
- // of which transactions are currently in pending.
215
- tag: 'pending',
216
- useAbsoluteNonce: useAbsoluteBalanceAndNonce,
217
- }))
207
+ (await asset.baseAsset.getNonce({ asset, fromAddress, walletAccount }))
218
208
 
219
209
  const createTxParams = {
220
210
  assetClientInterface,