@exodus/ethereum-api 8.21.2 → 8.22.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 +22 -0
- package/README.md +3 -0
- package/package.json +3 -3
- package/src/create-asset-plugin-factory.js +9 -57
- package/src/create-asset.js +6 -2
- package/src/exodus-eth-server/clarity-v2.js +3 -1
- package/src/exodus-eth-server/clarity.js +13 -7
- package/src/fee-data-factory.js +56 -0
- package/src/tx-log/ethereum-no-history-monitor.js +3 -2
- package/src/tx-send/nonce-utils.js +18 -0
- package/src/tx-send/tx-send.js +28 -28
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
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.22.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.21.3...@exodus/ethereum-api@8.22.0) (2024-12-02)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* feat: gasPriceMaximumRate in evm fee data (#4578)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [8.21.3](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.21.2...@exodus/ethereum-api@8.21.3) (2024-11-27)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
* fix: handling JSON RPC responses in Clarity V2 (#4587)
|
|
23
|
+
|
|
24
|
+
* fix: improve nonce calculation for EVMs and fix drop txs in no history (#4583)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
## [8.21.2](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.21.1...@exodus/ethereum-api@8.21.2) (2024-11-15)
|
|
7
29
|
|
|
8
30
|
**Note:** Version bump only for package @exodus/ethereum-api
|
package/README.md
ADDED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/ethereum-api",
|
|
3
|
-
"version": "8.
|
|
4
|
-
"description": "Ethereum
|
|
3
|
+
"version": "8.22.0",
|
|
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",
|
|
7
7
|
"files": [
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"type": "git",
|
|
65
65
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "9888fd7b7356fd52f0bf92e505071565c8fa19ce"
|
|
68
68
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { createMetaDef } from '@exodus/asset'
|
|
2
|
-
import { FeeData } from '@exodus/asset-lib'
|
|
3
|
-
import { UnitType } from '@exodus/currency'
|
|
4
2
|
import assert from 'minimalistic-assert'
|
|
5
3
|
|
|
6
4
|
import { createAssetFactory } from './create-asset.js'
|
|
@@ -27,8 +25,6 @@ export const createAssetPluginFactory = (config) => {
|
|
|
27
25
|
[ticker]: decimals || 18,
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
const currency = UnitType.create(units)
|
|
31
|
-
|
|
32
28
|
// adds lots of validation in config
|
|
33
29
|
const tokenOverrides = (token) => ({
|
|
34
30
|
...token,
|
|
@@ -43,7 +39,7 @@ export const createAssetPluginFactory = (config) => {
|
|
|
43
39
|
}
|
|
44
40
|
|
|
45
41
|
const assetType = 'ETHEREUM_LIKE'
|
|
46
|
-
const {
|
|
42
|
+
const { assetsList } = createMetaDef({
|
|
47
43
|
assetParams: {
|
|
48
44
|
...meta,
|
|
49
45
|
name,
|
|
@@ -56,61 +52,17 @@ export const createAssetPluginFactory = (config) => {
|
|
|
56
52
|
tokensParams: meta.tokens || [],
|
|
57
53
|
tokenOverrides,
|
|
58
54
|
})
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
gasPriceEconomicalRate: 0.8,
|
|
65
|
-
gasPriceMinimumRate: 0.6,
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (config.eip1559Enabled === true) {
|
|
69
|
-
assert(config.baseFeePerGas, 'baseFeePerGas is required')
|
|
70
|
-
const baseFeePerGas = currency.parse(config.baseFeePerGas)
|
|
71
|
-
const gasPrice = config.gasPrice ? currency.parse(config.gasPrice) : baseFeePerGas.mul(1.5)
|
|
72
|
-
return {
|
|
73
|
-
gasPrice: gasPrice.toBaseString({ unit: true }),
|
|
74
|
-
baseFeePerGas: baseFeePerGas.toBaseString({ unit: true }),
|
|
75
|
-
max: gasPrice.mul(5).toBaseString({ unit: true }),
|
|
76
|
-
min: gasPrice.div(5).toBaseString({ unit: true }),
|
|
77
|
-
eip1559Enabled: config.eip1559Enabled,
|
|
78
|
-
...shared,
|
|
79
|
-
...config.feeData,
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (config.eip1559Enabled === false) {
|
|
84
|
-
assert(config.gasPrice, 'gasPrice is required')
|
|
85
|
-
const gasPrice = currency.parse(config.gasPrice)
|
|
86
|
-
return {
|
|
87
|
-
gasPrice: gasPrice.toBaseString({ unit: true }),
|
|
88
|
-
max: gasPrice.mul(5).toBaseString({ unit: true }),
|
|
89
|
-
min: gasPrice.div(5).toBaseString({ unit: true }),
|
|
90
|
-
eip1559Enabled: config.eip1559Enabled,
|
|
91
|
-
...shared,
|
|
92
|
-
...config.feeData,
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
gasPrice: '0.02 Gwei',
|
|
98
|
-
baseFeePerGas: '0.02 Gwei',
|
|
99
|
-
eip1559Enabled: true,
|
|
100
|
-
...shared,
|
|
55
|
+
const feeDataConfig = Object.fromEntries(
|
|
56
|
+
Object.entries({
|
|
57
|
+
gasPrice: config.gasPrice,
|
|
58
|
+
baseFeePerGas: config.baseFeePerGas,
|
|
59
|
+
eip1559Enabled: config.eip1559Enabled,
|
|
101
60
|
...config.feeData,
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const feeData = new FeeData({
|
|
106
|
-
config: resolveFeeDataConfigDefaults(),
|
|
107
|
-
mainKey: 'gasPrice',
|
|
108
|
-
currency: asset.currency,
|
|
109
|
-
})
|
|
110
|
-
|
|
61
|
+
}).filter(([_, value]) => value !== undefined)
|
|
62
|
+
)
|
|
111
63
|
const createAsset = createAssetFactory({
|
|
112
64
|
assetsList,
|
|
113
|
-
|
|
65
|
+
feeDataConfig,
|
|
114
66
|
...config.plugin,
|
|
115
67
|
})
|
|
116
68
|
|
package/src/create-asset.js
CHANGED
|
@@ -23,6 +23,7 @@ import ms from 'ms'
|
|
|
23
23
|
import { addressHasHistoryFactory } from './address-has-history.js'
|
|
24
24
|
import { createTokenFactory } from './create-token-factory.js'
|
|
25
25
|
import { createEvmServer } from './exodus-eth-server/index.js'
|
|
26
|
+
import { createFeeData } from './fee-data-factory.js'
|
|
26
27
|
import { createGetBalanceForAddress } from './get-balance-for-address.js'
|
|
27
28
|
import { getBalancesFactory } from './get-balances.js'
|
|
28
29
|
import { getEffectiveGasPrice, getFeeFactory } from './get-fee.js'
|
|
@@ -47,7 +48,8 @@ export const createAssetFactory = ({
|
|
|
47
48
|
customCreateGetKeyIdentifier,
|
|
48
49
|
customTokens: defaultCustomTokens = true,
|
|
49
50
|
erc20FuelBuffer,
|
|
50
|
-
feeData,
|
|
51
|
+
feeData: providedFeeData,
|
|
52
|
+
feeDataConfig,
|
|
51
53
|
feeMonitorInterval,
|
|
52
54
|
fuelThreshold,
|
|
53
55
|
isMaxFeeAsset = false,
|
|
@@ -62,11 +64,13 @@ export const createAssetFactory = ({
|
|
|
62
64
|
forceGasLimitEstimation = false,
|
|
63
65
|
}) => {
|
|
64
66
|
assert(assetsList, 'assetsList is required')
|
|
65
|
-
assert(
|
|
67
|
+
assert(providedFeeData || feeDataConfig, 'feeData or feeDataConfig is required')
|
|
66
68
|
assert(serverUrl, 'serverUrl is required')
|
|
67
69
|
assert(confirmationsNumber, 'confirmationsNumber is required')
|
|
68
70
|
|
|
69
71
|
const base = assetsList.find((asset) => asset.name === asset.baseAssetName)
|
|
72
|
+
|
|
73
|
+
const feeData = providedFeeData || createFeeData({ currency: base.currency, feeDataConfig })
|
|
70
74
|
assert(base, 'base is required')
|
|
71
75
|
|
|
72
76
|
const chainId = base.chainId
|
|
@@ -108,7 +108,9 @@ export default class ClarityServerV2 extends ClarityServer {
|
|
|
108
108
|
fetchOptions.body = JSON.stringify(body)
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
const response = await fetchJson(url, fetchOptions)
|
|
112
|
+
|
|
113
|
+
return this.handleJsonRPCResponse(response)
|
|
112
114
|
}
|
|
113
115
|
|
|
114
116
|
async sendRawTransaction(...params) {
|
|
@@ -86,6 +86,18 @@ export default class ClarityServer extends EventEmitter {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
// See https://www.jsonrpc.org/specification#response_object for details.
|
|
90
|
+
handleJsonRPCResponse(response) {
|
|
91
|
+
const result = response?.result
|
|
92
|
+
const error = response?.error
|
|
93
|
+
if (error || result === undefined) {
|
|
94
|
+
const message = error?.message || error?.code || 'no result'
|
|
95
|
+
throw new Error(`Bad rpc response: ${message}`)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return result
|
|
99
|
+
}
|
|
100
|
+
|
|
89
101
|
async getAllTransactions(params) {
|
|
90
102
|
const transactions = { pending: [], confirmed: [] }
|
|
91
103
|
const cursor = await this.getTransactions({
|
|
@@ -176,14 +188,8 @@ export default class ClarityServer extends EventEmitter {
|
|
|
176
188
|
|
|
177
189
|
async sendRequest(request) {
|
|
178
190
|
const response = await this.sendRpcRequest(request)
|
|
179
|
-
const result = response?.result
|
|
180
|
-
const error = response?.error
|
|
181
|
-
if (error || result === undefined) {
|
|
182
|
-
const message = error?.message || error?.code || 'no result'
|
|
183
|
-
throw new Error(`Bad rpc response: ${message}`)
|
|
184
|
-
}
|
|
185
191
|
|
|
186
|
-
return
|
|
192
|
+
return this.handleJsonRPCResponse(response)
|
|
187
193
|
}
|
|
188
194
|
|
|
189
195
|
async isContract(address) {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { FeeData } from '@exodus/asset-lib'
|
|
2
|
+
import assert from 'minimalistic-assert'
|
|
3
|
+
|
|
4
|
+
const createFeeDataConfigDefaults = ({ currency, feeDataConfig }) => {
|
|
5
|
+
const shared = {
|
|
6
|
+
tipGasPrice: '0 Gwei',
|
|
7
|
+
fuelThreshold: '0 Gwei',
|
|
8
|
+
gasPriceEconomicalRate: 0.8,
|
|
9
|
+
gasPriceMinimumRate: 0.6,
|
|
10
|
+
gasPriceMaximumRate: 1.3,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (feeDataConfig.eip1559Enabled === true) {
|
|
14
|
+
assert(feeDataConfig.baseFeePerGas, 'baseFeePerGas is required')
|
|
15
|
+
const baseFeePerGas = currency.parse(feeDataConfig.baseFeePerGas)
|
|
16
|
+
const gasPrice = feeDataConfig.gasPrice
|
|
17
|
+
? currency.parse(feeDataConfig.gasPrice)
|
|
18
|
+
: baseFeePerGas.mul(1.5)
|
|
19
|
+
return {
|
|
20
|
+
gasPrice: gasPrice.toBaseString({ unit: true }),
|
|
21
|
+
baseFeePerGas: baseFeePerGas.toBaseString({ unit: true }),
|
|
22
|
+
eip1559Enabled: feeDataConfig.eip1559Enabled,
|
|
23
|
+
...shared,
|
|
24
|
+
...feeDataConfig,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (feeDataConfig.eip1559Enabled === false) {
|
|
29
|
+
assert(feeDataConfig.gasPrice, 'gasPrice is required')
|
|
30
|
+
const gasPrice = currency.parse(feeDataConfig.gasPrice)
|
|
31
|
+
return {
|
|
32
|
+
gasPrice: gasPrice.toBaseString({ unit: true }),
|
|
33
|
+
max: gasPrice.mul(5).toBaseString({ unit: true }),
|
|
34
|
+
min: gasPrice.div(5).toBaseString({ unit: true }),
|
|
35
|
+
eip1559Enabled: feeDataConfig.eip1559Enabled,
|
|
36
|
+
...shared,
|
|
37
|
+
...feeDataConfig,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
gasPrice: '0.02 Gwei',
|
|
43
|
+
baseFeePerGas: '0.02 Gwei',
|
|
44
|
+
eip1559Enabled: true,
|
|
45
|
+
...shared,
|
|
46
|
+
...feeDataConfig,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const createFeeData = ({ currency, feeDataConfig }) => {
|
|
51
|
+
return new FeeData({
|
|
52
|
+
config: createFeeDataConfigDefaults({ currency, feeDataConfig }),
|
|
53
|
+
mainKey: 'gasPrice',
|
|
54
|
+
currency,
|
|
55
|
+
})
|
|
56
|
+
}
|
|
@@ -137,12 +137,13 @@ export class EthereumNoHistoryMonitor extends BaseMonitor {
|
|
|
137
137
|
|
|
138
138
|
for (const { tx, assetName } of pendingTransactions) {
|
|
139
139
|
const txFromNode = pendingTxsFromNode[tx.txId]
|
|
140
|
-
|
|
140
|
+
const isConfirmed = Boolean(txFromNode?.blockHash)
|
|
141
|
+
if (now - tx.date.getTime() > UNCONFIRMED_TX_LIMIT && !isConfirmed) {
|
|
141
142
|
txsToRemove.push({
|
|
142
143
|
tx,
|
|
143
144
|
assetSource: { asset: assetName, walletAccount },
|
|
144
145
|
})
|
|
145
|
-
} else if (
|
|
146
|
+
} else if (isConfirmed) {
|
|
146
147
|
txsToUpdate.push({
|
|
147
148
|
tx: { ...tx, confirmations: 1 },
|
|
148
149
|
assetSource: { asset: assetName, walletAccount },
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getNonce } from '../eth-like-util.js'
|
|
2
|
+
|
|
3
|
+
export const resolveNonce = async ({ asset, fromAddress, providedNonce, txLog, triedNonce }) => {
|
|
4
|
+
const nonceFromNode = asset.baseAsset?.api?.features?.noHistory
|
|
5
|
+
? await getNonce({ asset: asset.baseAsset, address: fromAddress, tag: 'latest' }) // maybe 'pending' to unconfirmed txs
|
|
6
|
+
: 0
|
|
7
|
+
|
|
8
|
+
const nonceFromLog = [...txLog]
|
|
9
|
+
.filter((tx) => tx.sent && !tx.dropped && tx.data.nonce != null)
|
|
10
|
+
.reduce((nonce, tx) => Math.max(tx.data.nonce + 1, nonce), 0)
|
|
11
|
+
|
|
12
|
+
return Math.max(
|
|
13
|
+
nonceFromNode,
|
|
14
|
+
nonceFromLog,
|
|
15
|
+
providedNonce ?? 0,
|
|
16
|
+
triedNonce === undefined ? 0 : triedNonce + 1
|
|
17
|
+
)
|
|
18
|
+
}
|
package/src/tx-send/tx-send.js
CHANGED
|
@@ -4,9 +4,10 @@ import { calculateBumpedGasPrice, isEthereumLikeToken, normalizeTxId } from '@ex
|
|
|
4
4
|
import assert from 'minimalistic-assert'
|
|
5
5
|
|
|
6
6
|
import * as ErrorWrapper from '../error-wrapper.js'
|
|
7
|
-
import {
|
|
7
|
+
import { transactionExists } from '../eth-like-util.js'
|
|
8
8
|
import { getNftArguments } from '../nft-utils.js'
|
|
9
9
|
import getFeeInfo from './get-fee-info.js'
|
|
10
|
+
import { resolveNonce } from './nonce-utils.js'
|
|
10
11
|
|
|
11
12
|
const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
12
13
|
assert(assetClientInterface, 'assetClientInterface is required')
|
|
@@ -21,7 +22,7 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
|
21
22
|
shouldLog = true,
|
|
22
23
|
keepTxInput,
|
|
23
24
|
txInput,
|
|
24
|
-
nonce:
|
|
25
|
+
nonce: providedNonce,
|
|
25
26
|
bumpTxId,
|
|
26
27
|
customFee,
|
|
27
28
|
isSendAll,
|
|
@@ -56,17 +57,18 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
|
56
57
|
amount = asset.baseAsset.currency.ZERO
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
let
|
|
60
|
+
let bumpNonce
|
|
60
61
|
|
|
61
62
|
let eip1559Enabled = feeData.eip1559Enabled
|
|
62
63
|
|
|
64
|
+
const baseAssetTxLog = await assetClientInterface.getTxLog({
|
|
65
|
+
assetName: baseAsset.name,
|
|
66
|
+
walletAccount,
|
|
67
|
+
})
|
|
68
|
+
|
|
63
69
|
// `replacedTx` is always an ETH/ETC transaction (not a token)
|
|
64
70
|
let replacedTx, replacedTokenTx
|
|
65
71
|
if (bumpTxId) {
|
|
66
|
-
const baseAssetTxLog = await assetClientInterface.getTxLog({
|
|
67
|
-
assetName: baseAsset.name,
|
|
68
|
-
walletAccount,
|
|
69
|
-
})
|
|
70
72
|
replacedTx = baseAssetTxLog.get(bumpTxId)
|
|
71
73
|
if (!replacedTx || !replacedTx.pending) {
|
|
72
74
|
throw new Error(`Cannot bump transaction ${bumpTxId}: not found or confirmed`)
|
|
@@ -98,21 +100,25 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
|
98
100
|
feeOpts.gasPrice = bumpedGasPrice
|
|
99
101
|
feeOpts.tipGasPrice = bumpedTipGasPrice
|
|
100
102
|
eip1559Enabled = feeData.eip1559Enabled && feeOpts.tipGasPrice
|
|
101
|
-
|
|
103
|
+
bumpNonce = replacedTx.data.nonce
|
|
102
104
|
txInput = replacedTokenTx ? null : replacedTx.data.data || '0x'
|
|
103
105
|
feeAmount = feeOpts.gasPrice.mul(feeOpts.gasLimit)
|
|
104
|
-
if (
|
|
106
|
+
if (bumpNonce === undefined) {
|
|
105
107
|
throw new Error(`Cannot bump transaction ${bumpTxId}: data object seems to be corrupted`)
|
|
106
108
|
}
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
const resolvedNonce =
|
|
112
|
+
bumpNonce ??
|
|
113
|
+
(await resolveNonce({ asset, fromAddress, providedNonce, txLog: baseAssetTxLog }))
|
|
114
|
+
|
|
109
115
|
const createTxParams = {
|
|
110
116
|
assetClientInterface,
|
|
111
117
|
asset,
|
|
112
118
|
walletAccount,
|
|
113
119
|
toAddress: contractAddress || address,
|
|
114
120
|
amount,
|
|
115
|
-
nonce:
|
|
121
|
+
nonce: resolvedNonce,
|
|
116
122
|
fromAddress,
|
|
117
123
|
eip1559Enabled,
|
|
118
124
|
customFee,
|
|
@@ -157,8 +163,13 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
|
157
163
|
} else if (nonceTooLowErr) {
|
|
158
164
|
console.info('trying to send again...') // inject logger factory from platform
|
|
159
165
|
// let's try to fix the nonce issue
|
|
160
|
-
|
|
161
|
-
|
|
166
|
+
nonce = await resolveNonce({
|
|
167
|
+
asset,
|
|
168
|
+
fromAddress,
|
|
169
|
+
providedNonce,
|
|
170
|
+
txLog: baseAssetTxLog,
|
|
171
|
+
triedNonce: nonce,
|
|
172
|
+
})
|
|
162
173
|
;({ txId, rawTx } = await createTx({ ...createTxParams, nonce }))
|
|
163
174
|
|
|
164
175
|
try {
|
|
@@ -247,7 +258,7 @@ const txSendFactory = ({ assetClientInterface, createUnsignedTx }) => {
|
|
|
247
258
|
})
|
|
248
259
|
}
|
|
249
260
|
|
|
250
|
-
return { txId }
|
|
261
|
+
return { txId, nonce }
|
|
251
262
|
}
|
|
252
263
|
}
|
|
253
264
|
|
|
@@ -268,6 +279,10 @@ const createTx = async ({
|
|
|
268
279
|
feeOpts,
|
|
269
280
|
createUnsignedTx,
|
|
270
281
|
}) => {
|
|
282
|
+
assert(
|
|
283
|
+
nonce !== undefined && typeof nonce === 'number',
|
|
284
|
+
'Nonce must be provided when creating a tx'
|
|
285
|
+
)
|
|
271
286
|
const isToken = isEthereumLikeToken(asset)
|
|
272
287
|
|
|
273
288
|
if (txInput && isToken && !keepTxInput)
|
|
@@ -309,21 +324,6 @@ const createTx = async ({
|
|
|
309
324
|
// gasLimit = customGasLimit
|
|
310
325
|
}
|
|
311
326
|
|
|
312
|
-
if (asset.baseAsset?.api?.hasFeature?.('noHistory')) {
|
|
313
|
-
nonce = await getNonce({ asset: asset.baseAsset, address: fromAddress })
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
if (nonce === undefined) {
|
|
317
|
-
// Calculate latest nonce from base asset's TX log
|
|
318
|
-
const baseAssetTxLog = await assetClientInterface.getTxLog({
|
|
319
|
-
assetName: asset.baseAsset.name,
|
|
320
|
-
walletAccount,
|
|
321
|
-
})
|
|
322
|
-
nonce = [...baseAssetTxLog]
|
|
323
|
-
.filter((tx) => tx.sent && !tx.dropped && tx.data.nonce != null)
|
|
324
|
-
.reduce((nonce, tx) => Math.max(tx.data.nonce + 1, nonce), 0)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
327
|
const unsignedTx = await createUnsignedTx({
|
|
328
328
|
asset,
|
|
329
329
|
walletAccount,
|