@exodus/ethereum-api 8.53.3 → 8.53.5
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 +18 -0
- package/package.json +4 -3
- package/src/tx-create.js +11 -1
- package/src/tx-log/get-optimistic-txlog-effects.js +31 -19
- package/src/tx-send/tx-send.js +11 -34
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.53.5](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.53.4...@exodus/ethereum-api@8.53.5) (2025-10-17)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: default toTxAddress to be the token address if not provided (#6729)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [8.53.4](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.53.3...@exodus/ethereum-api@8.53.4) (2025-10-06)
|
|
17
|
+
|
|
18
|
+
**Note:** Version bump only for package @exodus/ethereum-api
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
6
24
|
## [8.53.3](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.53.2...@exodus/ethereum-api@8.53.3) (2025-10-02)
|
|
7
25
|
|
|
8
26
|
**Note:** Version bump only for package @exodus/ethereum-api
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/ethereum-api",
|
|
3
|
-
"version": "8.53.
|
|
3
|
+
"version": "8.53.5",
|
|
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",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"homepage": "https://github.com/ExodusMovement/assets/tree/master/ethereum/ethereum-api",
|
|
15
15
|
"publishConfig": {
|
|
16
|
-
"access": "public"
|
|
16
|
+
"access": "public",
|
|
17
|
+
"provenance": false
|
|
17
18
|
},
|
|
18
19
|
"scripts": {
|
|
19
20
|
"test": "run -T exodus-test --jest",
|
|
@@ -66,5 +67,5 @@
|
|
|
66
67
|
"type": "git",
|
|
67
68
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
68
69
|
},
|
|
69
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "48ee2473ddc98a5eb52a69bba220910263d21a45"
|
|
70
71
|
}
|
package/src/tx-create.js
CHANGED
|
@@ -271,7 +271,17 @@ export const createTxFactory = ({ chainId, assetClientInterface, useAbsoluteNonc
|
|
|
271
271
|
|
|
272
272
|
const resolvedGasPrice = providedGasPrice ?? maybeGasPrice
|
|
273
273
|
|
|
274
|
-
|
|
274
|
+
// When sending a main asset, the transaction (tx) 'to' address is the receiver's address. No tx input is provided.
|
|
275
|
+
// When sending a token, the tx 'to' address is the asset.contract?.address. No tx input is provided; it's resolved locally.
|
|
276
|
+
// When DEX swapping a main asset, the exchange provides a txInput and a DEX address. Use the DEX address as the tx 'to' address.
|
|
277
|
+
// When DEX swapping a token, the exchange provides a txInput and a DEX address. Use the DEX address as the tx 'to' address.
|
|
278
|
+
// When CEX swapping a main asset, the exchange may provide a txInput and an address. Use this address as the tx 'to' address.
|
|
279
|
+
// When CEX swapping a token, the exchange may provide a txInput but not an address. In this case, the tx 'to' address is the token address.
|
|
280
|
+
|
|
281
|
+
const txToAddress =
|
|
282
|
+
isToken && !providedTxInput
|
|
283
|
+
? asset.contract.address
|
|
284
|
+
: providedToAddress || asset.contract?.address || ARBITRARY_ADDRESS
|
|
275
285
|
|
|
276
286
|
const isContractToAddress = await isContractAddressCached({ asset, address: txToAddress })
|
|
277
287
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { isEthereumLikeToken } from '@exodus/ethereum-lib'
|
|
1
|
+
import NumberUnit from '@exodus/currency'
|
|
2
|
+
import { isEthereumLikeToken, parseUnsignedTx } from '@exodus/ethereum-lib'
|
|
3
|
+
import { bufferToHex } from '@exodus/ethereumjs/util'
|
|
3
4
|
import assert from 'minimalistic-assert'
|
|
4
5
|
|
|
5
6
|
// Returns the most competitively priced pending
|
|
@@ -30,39 +31,50 @@ export const getHighestIncentivePendingTxByNonce = async ({
|
|
|
30
31
|
|
|
31
32
|
export const getOptimisticTxLogEffects = async ({
|
|
32
33
|
asset,
|
|
33
|
-
amount = asset.currency.ZERO,
|
|
34
34
|
assetClientInterface,
|
|
35
35
|
confirmations = 0,
|
|
36
|
-
feeAmount,
|
|
37
36
|
fromAddress,
|
|
38
|
-
gasLimit,
|
|
39
|
-
nonce,
|
|
40
37
|
txId,
|
|
41
|
-
|
|
42
|
-
tipGasPrice: maybeTipGasPrice,
|
|
38
|
+
unsignedTx,
|
|
43
39
|
walletAccount,
|
|
44
|
-
methodId,
|
|
45
40
|
}) => {
|
|
46
|
-
assert(isNumberUnit(amount), 'expected NumberUnit amount')
|
|
47
41
|
assert(asset, 'expected asset')
|
|
48
42
|
assert(assetClientInterface, 'expected assetClientInterface')
|
|
49
43
|
assert(Number.isInteger(confirmations), 'expected integer confirmations')
|
|
50
|
-
assert(isNumberUnit(feeAmount), 'expected feeAmount')
|
|
51
44
|
assert(typeof fromAddress === 'string', 'expected string fromAddress')
|
|
52
|
-
assert(Number.isInteger(gasLimit), 'expected integer gasLimit')
|
|
53
|
-
assert(Number.isInteger(nonce), 'expected integer nonce')
|
|
54
|
-
assert(typeof toAddress === 'string', 'expected string toAddress')
|
|
55
45
|
assert(txId, 'expected txId')
|
|
46
|
+
assert(unsignedTx, 'expected unsignedTx')
|
|
56
47
|
assert(walletAccount, 'expected walletAccount')
|
|
57
48
|
|
|
58
|
-
|
|
49
|
+
// this converts an transactionBuffer to values we can use when creating the tx logs
|
|
50
|
+
const parsedTx = parseUnsignedTx({ asset, unsignedTx })
|
|
59
51
|
|
|
60
|
-
const
|
|
52
|
+
const { nonce } = parsedTx
|
|
53
|
+
assert(Number.isInteger(nonce), 'expected integer nonce')
|
|
54
|
+
|
|
55
|
+
const amount = parsedTx.amount || asset.currency.ZERO
|
|
56
|
+
assert(amount instanceof NumberUnit, 'expected NumberUnit amount')
|
|
57
|
+
|
|
58
|
+
const feeAmount = parsedTx.fee
|
|
59
|
+
assert(feeAmount instanceof NumberUnit, 'expected feeAmount')
|
|
60
|
+
|
|
61
|
+
const maybeTipGasPrice = parsedTx.tipGasPrice
|
|
62
|
+
if (maybeTipGasPrice) {
|
|
63
|
+
assert(maybeTipGasPrice instanceof NumberUnit, 'expected NumberUnit tipGasPrice')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const gasLimit = parsedTx.gasLimit
|
|
67
|
+
assert(Number.isInteger(gasLimit), 'expected integer gasLimit')
|
|
68
|
+
|
|
69
|
+
const toAddress = parsedTx.to
|
|
70
|
+
assert(typeof toAddress === 'string', 'expected string toAddress')
|
|
71
|
+
|
|
72
|
+
const data = parsedTx.data
|
|
73
|
+
const methodId = data ? bufferToHex(data).slice(0, 10) : undefined
|
|
61
74
|
|
|
62
|
-
// TODO: This is incorrect for token transfers.
|
|
63
75
|
const selfSend = fromAddress.toLowerCase() === toAddress.toLowerCase()
|
|
64
76
|
|
|
65
|
-
|
|
77
|
+
const baseAsset = asset.baseAsset
|
|
66
78
|
|
|
67
79
|
const maybeTxToReplace = await getHighestIncentivePendingTxByNonce({
|
|
68
80
|
asset,
|
|
@@ -128,5 +140,5 @@ export const getOptimisticTxLogEffects = async ({
|
|
|
128
140
|
},
|
|
129
141
|
].filter(Boolean)
|
|
130
142
|
|
|
131
|
-
return { optimisticTxLogEffects }
|
|
143
|
+
return { optimisticTxLogEffects, nonce }
|
|
132
144
|
}
|
package/src/tx-send/tx-send.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { normalizeTxId, parseUnsignedTx, updateNonce } from '@exodus/ethereum-lib'
|
|
2
|
-
import { bufferToHex } from '@exodus/ethereumjs/util'
|
|
3
2
|
import assert from 'minimalistic-assert'
|
|
4
3
|
|
|
5
4
|
import * as ErrorWrapper from '../error-wrapper.js'
|
|
@@ -40,17 +39,8 @@ const txSendFactory = ({ assetClientInterface, createTx }) => {
|
|
|
40
39
|
|
|
41
40
|
const { unsignedTx } = await resolveUnsignedTx()
|
|
42
41
|
|
|
43
|
-
// this converts an transactionBuffer to values we can use when creating the tx logs
|
|
44
42
|
const parsedTx = parseUnsignedTx({ asset, unsignedTx })
|
|
45
|
-
|
|
46
|
-
let nonce = parsedTx.nonce
|
|
47
|
-
|
|
48
|
-
const tipGasPrice = parsedTx.tipGasPrice
|
|
49
|
-
const feeAmount = parsedTx.fee
|
|
50
|
-
const gasLimit = parsedTx.gasLimit
|
|
51
|
-
const amount = parsedTx.amount
|
|
52
43
|
const toAddress = parsedTx.to
|
|
53
|
-
const data = parsedTx.data
|
|
54
44
|
|
|
55
45
|
// unknown data from buffer...
|
|
56
46
|
const fromAddress = unsignedTx.txMeta.fromAddress
|
|
@@ -66,18 +56,8 @@ const txSendFactory = ({ assetClientInterface, createTx }) => {
|
|
|
66
56
|
walletAccount,
|
|
67
57
|
})
|
|
68
58
|
|
|
69
|
-
const isPrivate = Boolean(legacyParams?.options?.isPrivate)
|
|
70
|
-
|
|
71
|
-
if (isPrivate && typeof baseAsset.broadcastPrivateTx !== 'function') {
|
|
72
|
-
throw new Error(
|
|
73
|
-
`unable to send private transaction - private mempools are not enabled for ${baseAsset.name}`
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const broadcastTx = isPrivate ? baseAsset.broadcastPrivateTx : baseAsset.api.broadcastTx
|
|
78
|
-
|
|
79
59
|
try {
|
|
80
|
-
await broadcastTx(rawTx.toString('hex'))
|
|
60
|
+
await baseAsset.api.broadcastTx(rawTx.toString('hex'))
|
|
81
61
|
} catch (err) {
|
|
82
62
|
const nonceTooLowErr = err.message.match(/nonce (is |)too low/i)
|
|
83
63
|
const insufficientFundsErr = err.message.match(/insufficient funds/i)
|
|
@@ -112,7 +92,7 @@ const txSendFactory = ({ assetClientInterface, createTx }) => {
|
|
|
112
92
|
asset,
|
|
113
93
|
fromAddress,
|
|
114
94
|
walletAccount,
|
|
115
|
-
triedNonce: nonce,
|
|
95
|
+
triedNonce: parsedTx.nonce,
|
|
116
96
|
forceFromNode: true,
|
|
117
97
|
})
|
|
118
98
|
|
|
@@ -121,8 +101,6 @@ const txSendFactory = ({ assetClientInterface, createTx }) => {
|
|
|
121
101
|
transactionBuffer: unsignedTx.txData.transactionBuffer,
|
|
122
102
|
newNonce,
|
|
123
103
|
})
|
|
124
|
-
|
|
125
|
-
nonce = newNonce
|
|
126
104
|
;({ txId, rawTx } = await signTx({ asset, unsignedTx, walletAccount }))
|
|
127
105
|
|
|
128
106
|
try {
|
|
@@ -143,24 +121,23 @@ const txSendFactory = ({ assetClientInterface, createTx }) => {
|
|
|
143
121
|
hint: 'retry:broadcastTx',
|
|
144
122
|
})
|
|
145
123
|
}
|
|
124
|
+
} else {
|
|
125
|
+
// If none of the above apply, terminate with a general error.
|
|
126
|
+
throw new ErrorWrapper.EthLikeError({
|
|
127
|
+
message: err.message,
|
|
128
|
+
reason: ErrorWrapper.reasons.broadcastTxFailed,
|
|
129
|
+
hint: 'broadcastTx',
|
|
130
|
+
})
|
|
146
131
|
}
|
|
147
132
|
}
|
|
148
133
|
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
const { optimisticTxLogEffects } = await getOptimisticTxLogEffects({
|
|
152
|
-
amount,
|
|
134
|
+
const { nonce, optimisticTxLogEffects } = await getOptimisticTxLogEffects({
|
|
153
135
|
asset,
|
|
154
136
|
assetClientInterface,
|
|
155
|
-
feeAmount,
|
|
156
137
|
fromAddress,
|
|
157
|
-
gasLimit,
|
|
158
|
-
nonce,
|
|
159
138
|
txId,
|
|
160
|
-
|
|
161
|
-
tipGasPrice,
|
|
139
|
+
unsignedTx,
|
|
162
140
|
walletAccount,
|
|
163
|
-
methodId,
|
|
164
141
|
})
|
|
165
142
|
|
|
166
143
|
// NOTE: `optimisticTxLogEffects` **must** be written sequentially.
|