@exodus/ethereum-api 8.75.0 → 8.75.1
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 +10 -0
- package/package.json +2 -2
- package/src/allowance/index.js +19 -19
- package/src/create-asset-utils.js +131 -5
- package/src/create-asset.js +16 -8
- package/src/gas-estimation.js +1 -1
- package/src/staking/ethereum/service.js +18 -53
- package/src/tx-send/tx-send.js +9 -12
- package/src/tx-sign/index.js +17 -0
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.75.1](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.75.0...@exodus/ethereum-api@8.75.1) (2026-05-19)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: use correct fromAddress for gasLimit multiplication (#8078)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
6
16
|
## [8.75.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.74.1...@exodus/ethereum-api@8.75.0) (2026-05-13)
|
|
7
17
|
|
|
8
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/ethereum-api",
|
|
3
|
-
"version": "8.75.
|
|
3
|
+
"version": "8.75.1",
|
|
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",
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"type": "git",
|
|
68
68
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "ee5bf2d01055d8822c6421fa0ad4da84d4a33402"
|
|
71
71
|
}
|
package/src/allowance/index.js
CHANGED
|
@@ -120,11 +120,9 @@ export const buildLegacyApproveTx = async ({
|
|
|
120
120
|
const baseAsset = asset.baseAsset
|
|
121
121
|
|
|
122
122
|
return {
|
|
123
|
-
asset: baseAsset
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
amount: buffer2currency({ asset: baseAsset, value: unsignedTx.txData.value }),
|
|
127
|
-
},
|
|
123
|
+
asset: baseAsset,
|
|
124
|
+
address: unsignedTx.txData.to,
|
|
125
|
+
amount: buffer2currency({ asset: baseAsset, value: unsignedTx.txData.value }),
|
|
128
126
|
txInput: unsignedTx.txData.data,
|
|
129
127
|
gasPrice: buffer2currency({ asset: baseAsset, value: unsignedTx.txData.gasPrice }),
|
|
130
128
|
tipGasPrice: unsignedTx.txData.tipGasPrice
|
|
@@ -132,13 +130,12 @@ export const buildLegacyApproveTx = async ({
|
|
|
132
130
|
: undefined,
|
|
133
131
|
gasLimit: bufferToInt(unsignedTx.txData.gasLimit),
|
|
134
132
|
fromAddress: unsignedTx.txMeta.fromAddress,
|
|
135
|
-
silent: true,
|
|
136
133
|
}
|
|
137
134
|
}
|
|
138
135
|
|
|
139
136
|
// @deprecated use buildApproveTx instead
|
|
140
137
|
export const createApprove =
|
|
141
|
-
({ assetClientInterface
|
|
138
|
+
({ assetClientInterface } = Object.create(null)) =>
|
|
142
139
|
async ({
|
|
143
140
|
spenderAddress,
|
|
144
141
|
asset,
|
|
@@ -164,7 +161,16 @@ export const createApprove =
|
|
|
164
161
|
walletAccount,
|
|
165
162
|
})
|
|
166
163
|
|
|
167
|
-
const
|
|
164
|
+
const { unsignedTx } = await asset.baseAsset.api.createTx({
|
|
165
|
+
walletAccount,
|
|
166
|
+
...approveTx,
|
|
167
|
+
...extras,
|
|
168
|
+
})
|
|
169
|
+
const txData = await asset.baseAsset.api.sendTx({
|
|
170
|
+
asset: asset.baseAsset,
|
|
171
|
+
walletAccount,
|
|
172
|
+
unsignedTx,
|
|
173
|
+
})
|
|
168
174
|
|
|
169
175
|
if (!txData || !txData.txId) {
|
|
170
176
|
throw new Error(`Failed to approve ${asset.displayTicker} - ${spenderAddress}`)
|
|
@@ -185,25 +191,20 @@ export const createApprove =
|
|
|
185
191
|
walletAccount,
|
|
186
192
|
})
|
|
187
193
|
|
|
188
|
-
const { txId
|
|
189
|
-
assetName: asset.baseAsset.name,
|
|
190
|
-
unsignedTx,
|
|
191
|
-
walletAccount,
|
|
192
|
-
})
|
|
194
|
+
const { txId } = await asset.baseAsset.api.sendTx({ asset, walletAccount, unsignedTx })
|
|
193
195
|
|
|
194
|
-
await asset.baseAsset.api.broadcastTx(rawTx.toString('hex'))
|
|
195
196
|
return { txId }
|
|
196
197
|
}
|
|
197
198
|
|
|
198
199
|
const createSendApprovalAndWatchConfirmation =
|
|
199
|
-
({
|
|
200
|
+
({ watchTxConfirmation }) =>
|
|
200
201
|
async (data) => {
|
|
201
202
|
// To change the approve amount you first have to reduce the addresses`
|
|
202
203
|
// allowance to zero by calling `approve(_spender, 0)` if it is not
|
|
203
204
|
// already 0 to mitigate the race condition described here:
|
|
204
205
|
// see: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
|
|
205
206
|
// see: https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#code
|
|
206
|
-
const approve = createApprove(
|
|
207
|
+
const approve = createApprove()
|
|
207
208
|
const { txId } = await approve(data)
|
|
208
209
|
await watchTxConfirmation(
|
|
209
210
|
{ asset: data.asset.baseAsset.name, walletAccount: data.walletAccount },
|
|
@@ -215,11 +216,10 @@ const createSendApprovalAndWatchConfirmation =
|
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
export const createApproveSpendingTokens =
|
|
218
|
-
({
|
|
219
|
+
({ watchTxConfirmation }) =>
|
|
219
220
|
async (data) => {
|
|
220
221
|
const txIds = []
|
|
221
222
|
const sendApprovalAndWatchConfirmation = createSendApprovalAndWatchConfirmation({
|
|
222
|
-
sendTx,
|
|
223
223
|
watchTxConfirmation,
|
|
224
224
|
})
|
|
225
225
|
if (ZERO_ALLOWANCE_ASSETS.includes(data.asset.name) && !data.approveAmount.isZero) {
|
|
@@ -235,7 +235,7 @@ export const createApproveSpendingTokens =
|
|
|
235
235
|
data.gasLimit = Math.max(data.gasLimit || 0, APPROVAL_GAS_LIMIT)
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
const tokenApprovalTxId = await sendApprovalAndWatchConfirmation(
|
|
238
|
+
const tokenApprovalTxId = await sendApprovalAndWatchConfirmation(data)
|
|
239
239
|
txIds.push(tokenApprovalTxId)
|
|
240
240
|
|
|
241
241
|
return txIds
|
|
@@ -12,7 +12,9 @@ import { ClarityMonitorV2 } from './tx-log/clarity-monitor-v2.js'
|
|
|
12
12
|
import { ClarityTruncatedHistoryMonitor } from './tx-log/clarity-truncated-history-monitor.js'
|
|
13
13
|
import { EthereumMonitor } from './tx-log/ethereum-monitor.js'
|
|
14
14
|
import { EthereumNoHistoryMonitor } from './tx-log/ethereum-no-history-monitor.js'
|
|
15
|
+
import { getOptimisticTxLogEffects } from './tx-log/get-optimistic-txlog-effects.js'
|
|
15
16
|
import { BLOCK_TAG_LATEST, BLOCK_TAG_PENDING, resolveNonce } from './tx-send/nonce-utils.js'
|
|
17
|
+
import { signTx } from './tx-sign/index.js'
|
|
16
18
|
|
|
17
19
|
// Determines the appropriate `monitorType`, `serverUrl` and `monitorInterval`
|
|
18
20
|
// to use for a given config.
|
|
@@ -121,7 +123,126 @@ const broadcastPrivateBundleFactory =
|
|
|
121
123
|
return null
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
|
|
126
|
+
const assertSendPrivateTxProps = ({ asset, unsignedTx, walletAccount }) => {
|
|
127
|
+
assert(asset, 'expected asset')
|
|
128
|
+
assert(unsignedTx, 'expected unsignedTx')
|
|
129
|
+
assert(walletAccount, 'expected walletAccount')
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export const createTransactionPrivacyResult = ({
|
|
133
|
+
assetClientInterface,
|
|
134
|
+
broadcastPrivateBundle,
|
|
135
|
+
broadcastPrivateTx,
|
|
136
|
+
privacyServer,
|
|
137
|
+
}) => {
|
|
138
|
+
assert(assetClientInterface, 'expected assetClientInterface')
|
|
139
|
+
assert(typeof broadcastPrivateBundle === 'function')
|
|
140
|
+
assert(typeof broadcastPrivateTx === 'function')
|
|
141
|
+
assert(privacyServer, 'expected privacyServer')
|
|
142
|
+
|
|
143
|
+
const sendPrivateTx = async ({ asset, unsignedTx, walletAccount }) => {
|
|
144
|
+
assertSendPrivateTxProps({ asset, unsignedTx, walletAccount })
|
|
145
|
+
|
|
146
|
+
const { rawTx, txId } = await signTx({
|
|
147
|
+
asset,
|
|
148
|
+
assetClientInterface,
|
|
149
|
+
unsignedTx,
|
|
150
|
+
walletAccount,
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
await broadcastPrivateTx(rawTx.toString('hex'))
|
|
154
|
+
|
|
155
|
+
const fromAddress = unsignedTx.txMeta?.fromAddress
|
|
156
|
+
assert(typeof fromAddress === 'string', 'expected fromAddress')
|
|
157
|
+
|
|
158
|
+
const { nonce, optimisticTxLogEffects } = await getOptimisticTxLogEffects({
|
|
159
|
+
asset,
|
|
160
|
+
assetClientInterface,
|
|
161
|
+
fromAddress,
|
|
162
|
+
txId,
|
|
163
|
+
unsignedTx,
|
|
164
|
+
walletAccount,
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
for (const optimisticTxLogEffect of optimisticTxLogEffects) {
|
|
168
|
+
await assetClientInterface.updateTxLogAndNotify(optimisticTxLogEffect)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return { nonce, txId }
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const sendPrivateBundle = async ({ unsignedTxBundle }) => {
|
|
175
|
+
assert(
|
|
176
|
+
Array.isArray(unsignedTxBundle) && unsignedTxBundle.length > 0,
|
|
177
|
+
'expected non-empty unsignedTxBundle'
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
unsignedTxBundle.forEach(assertSendPrivateTxProps)
|
|
181
|
+
|
|
182
|
+
const signTxResults = await Promise.all(
|
|
183
|
+
unsignedTxBundle.map(({ asset, unsignedTx, walletAccount }) =>
|
|
184
|
+
signTx({ assetClientInterface, asset, unsignedTx, walletAccount })
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
const maybeBundleResult = await broadcastPrivateBundle({
|
|
189
|
+
txs: signTxResults.map(({ rawTx }) => rawTx.toString('hex')),
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
const bundleHash = maybeBundleResult?.bundleHash || undefined
|
|
193
|
+
|
|
194
|
+
const getOptimisticTxLogEffectsResults = []
|
|
195
|
+
|
|
196
|
+
for (const [i, { txId }] of signTxResults.entries()) {
|
|
197
|
+
const { asset, unsignedTx, walletAccount } = unsignedTxBundle[i]
|
|
198
|
+
|
|
199
|
+
const fromAddress = unsignedTx.txMeta?.fromAddress
|
|
200
|
+
assert(typeof fromAddress === 'string', 'expected fromAddress')
|
|
201
|
+
|
|
202
|
+
void getOptimisticTxLogEffectsResults.push(
|
|
203
|
+
await getOptimisticTxLogEffects({
|
|
204
|
+
asset,
|
|
205
|
+
assetClientInterface,
|
|
206
|
+
fromAddress,
|
|
207
|
+
txId,
|
|
208
|
+
unsignedTx,
|
|
209
|
+
walletAccount,
|
|
210
|
+
// TODO: use consistent naming
|
|
211
|
+
bundleId: bundleHash,
|
|
212
|
+
})
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const optimisticTxLogEffects = getOptimisticTxLogEffectsResults.flatMap(
|
|
217
|
+
({ optimisticTxLogEffects }) => optimisticTxLogEffects
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
for (const optimisticTxLogEffect of optimisticTxLogEffects) {
|
|
221
|
+
await assetClientInterface.updateTxLogAndNotify(optimisticTxLogEffect)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
bundleHash,
|
|
226
|
+
txIds: signTxResults.map(({ txId }) => txId),
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
broadcastPrivateBundle,
|
|
232
|
+
broadcastPrivateTx,
|
|
233
|
+
privacyServer,
|
|
234
|
+
sendPrivateTx,
|
|
235
|
+
sendPrivateBundle,
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export const createTransactionPrivacyFactory = ({
|
|
240
|
+
assetClientInterface,
|
|
241
|
+
assetName,
|
|
242
|
+
privacyRpcUrl,
|
|
243
|
+
}) => {
|
|
244
|
+
assert(assetClientInterface, 'expected assetClientInterface')
|
|
245
|
+
|
|
125
246
|
if (!privacyRpcUrl) return Object.create(null)
|
|
126
247
|
|
|
127
248
|
const privacyServer = createEvmServer({
|
|
@@ -130,11 +251,16 @@ export const createTransactionPrivacyFactory = ({ assetName, privacyRpcUrl }) =>
|
|
|
130
251
|
monitorType: 'no-history',
|
|
131
252
|
})
|
|
132
253
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
254
|
+
const broadcastPrivateBundle = broadcastPrivateBundleFactory({ privacyServer })
|
|
255
|
+
|
|
256
|
+
const broadcastPrivateTx = (...args) => privacyServer.sendRawTransaction(...args)
|
|
257
|
+
|
|
258
|
+
return createTransactionPrivacyResult({
|
|
259
|
+
assetClientInterface,
|
|
260
|
+
broadcastPrivateBundle,
|
|
261
|
+
broadcastPrivateTx,
|
|
136
262
|
privacyServer,
|
|
137
|
-
}
|
|
263
|
+
})
|
|
138
264
|
}
|
|
139
265
|
|
|
140
266
|
export const createHistoryMonitorFactory = ({
|
package/src/create-asset.js
CHANGED
|
@@ -195,11 +195,17 @@ export const createAssetFactory = ({
|
|
|
195
195
|
server,
|
|
196
196
|
})
|
|
197
197
|
|
|
198
|
-
const {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
198
|
+
const {
|
|
199
|
+
broadcastPrivateBundle,
|
|
200
|
+
broadcastPrivateTx,
|
|
201
|
+
privacyServer,
|
|
202
|
+
sendPrivateTx,
|
|
203
|
+
sendPrivateBundle,
|
|
204
|
+
} = createTransactionPrivacyFactory({
|
|
205
|
+
assetClientInterface,
|
|
206
|
+
assetName: asset.name,
|
|
207
|
+
privacyRpcUrl,
|
|
208
|
+
})
|
|
203
209
|
|
|
204
210
|
const features = {
|
|
205
211
|
accountState: true,
|
|
@@ -354,16 +360,18 @@ export const createAssetFactory = ({
|
|
|
354
360
|
chainId,
|
|
355
361
|
monitorType,
|
|
356
362
|
estimateL1DataFee,
|
|
357
|
-
broadcastPrivateBundle,
|
|
358
|
-
broadcastPrivateTx,
|
|
359
363
|
forceGasLimitEstimation,
|
|
360
364
|
eip7702Supported,
|
|
361
365
|
getEIP7702Delegation: (addr) => getEIP7702Delegation({ address: addr, server }),
|
|
362
366
|
getNonce,
|
|
363
|
-
privacyServer,
|
|
364
367
|
server,
|
|
365
368
|
...(erc20FuelBuffer && { erc20FuelBuffer }),
|
|
366
369
|
...(fuelThreshold && { fuelThreshold: asset.currency.defaultUnit(fuelThreshold) }),
|
|
370
|
+
broadcastPrivateBundle,
|
|
371
|
+
broadcastPrivateTx,
|
|
372
|
+
privacyServer,
|
|
373
|
+
sendPrivateTx,
|
|
374
|
+
sendPrivateBundle,
|
|
367
375
|
}
|
|
368
376
|
return overrideCallback({
|
|
369
377
|
asset: fullAsset,
|
package/src/gas-estimation.js
CHANGED
|
@@ -66,7 +66,6 @@ import NumberUnit from '@exodus/currency'
|
|
|
66
66
|
import assert from 'minimalistic-assert'
|
|
67
67
|
|
|
68
68
|
import { estimateGasLimit, scaleGasLimitEstimate } from '../../gas-estimation.js'
|
|
69
|
-
import { getOptimisticTxLogEffects } from '../../tx-log/get-optimistic-txlog-effects.js'
|
|
70
69
|
import { createWatchTx as defaultCreateWatch } from '../../watch-tx.js'
|
|
71
70
|
import { stakingProviderClientFactory } from '../staking-provider-client.js'
|
|
72
71
|
import { amountToCurrency, DISABLE_BALANCE_CHECKS, resolveFeeData } from '../utils/index.js'
|
|
@@ -281,8 +280,6 @@ export function createEthereumStakingService({
|
|
|
281
280
|
asset,
|
|
282
281
|
fromAddress: delegatorAddress,
|
|
283
282
|
walletAccount,
|
|
284
|
-
tag: 'latest',
|
|
285
|
-
forceFromNode: true,
|
|
286
283
|
})
|
|
287
284
|
|
|
288
285
|
return {
|
|
@@ -369,14 +366,12 @@ export function createEthereumStakingService({
|
|
|
369
366
|
plan: null,
|
|
370
367
|
gasLimit: null,
|
|
371
368
|
unsignedTx: null,
|
|
372
|
-
signedTx: null,
|
|
373
369
|
txId: null,
|
|
374
370
|
},
|
|
375
371
|
undelegate: {
|
|
376
372
|
plan: null,
|
|
377
373
|
gasLimit: null,
|
|
378
374
|
unsignedTx: null,
|
|
379
|
-
signedTx: null,
|
|
380
375
|
txId: null,
|
|
381
376
|
},
|
|
382
377
|
}
|
|
@@ -465,34 +460,16 @@ export function createEthereumStakingService({
|
|
|
465
460
|
revertOnSimulationError,
|
|
466
461
|
})
|
|
467
462
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const signedTx = await assetClientInterface.signTransaction({
|
|
474
|
-
assetName: asset.baseAsset.name,
|
|
475
|
-
unsignedTx: txStep.unsignedTx,
|
|
476
|
-
walletAccount,
|
|
477
|
-
})
|
|
478
|
-
const txId = `0x${signedTx.txId.toString('hex')}`
|
|
479
|
-
return [key, { signedTx, txId }]
|
|
480
|
-
})
|
|
481
|
-
)
|
|
482
|
-
|
|
483
|
-
for (const [key, { signedTx, txId }] of signedTxEntries) {
|
|
484
|
-
txSteps[key].signedTx = signedTx
|
|
485
|
-
txSteps[key].txId = txId
|
|
486
|
-
}
|
|
463
|
+
const unsignedTxBundle = createdTxEntries.map(([_, unsignedTx]) => ({
|
|
464
|
+
asset,
|
|
465
|
+
unsignedTx,
|
|
466
|
+
walletAccount,
|
|
467
|
+
}))
|
|
487
468
|
|
|
469
|
+
// 4. Sign transactions
|
|
470
|
+
//
|
|
488
471
|
// 5. Broadcast transactions via bundle and get bundle hash
|
|
489
|
-
|
|
490
|
-
txs: Object.values(txSteps)
|
|
491
|
-
.filter((txStep) => txStep.signedTx)
|
|
492
|
-
.map(({ signedTx }) => signedTx.rawTx),
|
|
493
|
-
})
|
|
494
|
-
const bundleHash = bundleResponse?.bundleHash
|
|
495
|
-
|
|
472
|
+
//
|
|
496
473
|
// 6. Optimistic tx-log effects: reflect tx presence and fee consumption only.
|
|
497
474
|
// The ETH returned to the user via the contract's internal transfer is not
|
|
498
475
|
// captured here — it will be picked up once the tx is confirmed on-chain.
|
|
@@ -518,26 +495,14 @@ export function createEthereumStakingService({
|
|
|
518
495
|
// That is incompatible with the current tx-log side-effect hook, which only
|
|
519
496
|
// receives tx-local data (method id, calldata, nonce, gas, etc.) and not
|
|
520
497
|
// staking snapshots or precomputed ETH-return amounts.
|
|
521
|
-
const
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
getOptimisticTxLogEffects({
|
|
526
|
-
asset: asset.baseAsset,
|
|
527
|
-
assetClientInterface,
|
|
528
|
-
fromAddress: delegatorAddress,
|
|
529
|
-
txId: txStep.txId,
|
|
530
|
-
unsignedTx: txStep.unsignedTx,
|
|
531
|
-
walletAccount,
|
|
532
|
-
bundleId: bundleHash ?? undefined,
|
|
533
|
-
})
|
|
534
|
-
)
|
|
535
|
-
)
|
|
498
|
+
const {
|
|
499
|
+
bundleHash,
|
|
500
|
+
txIds: [...txIds],
|
|
501
|
+
} = await asset.baseAsset.sendPrivateBundle({ unsignedTxBundle })
|
|
536
502
|
|
|
537
|
-
for (const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
}
|
|
503
|
+
for (const txStep of Object.values(txSteps)) {
|
|
504
|
+
if (!txStep.unsignedTx) continue
|
|
505
|
+
assert((txStep.txId = txIds.shift()), 'expected txId')
|
|
541
506
|
}
|
|
542
507
|
|
|
543
508
|
// Testnet assets do not support delegations tracking
|
|
@@ -770,7 +735,7 @@ export function createEthereumStakingService({
|
|
|
770
735
|
waitForConfirmation = false,
|
|
771
736
|
feeData,
|
|
772
737
|
}) {
|
|
773
|
-
const
|
|
738
|
+
const { unsignedTx } = await asset.baseAsset.api.createTx({
|
|
774
739
|
asset,
|
|
775
740
|
walletAccount,
|
|
776
741
|
address: to,
|
|
@@ -781,9 +746,9 @@ export function createEthereumStakingService({
|
|
|
781
746
|
// HACK: Override the `tipGasPrice` to use a custom `maxPriorityFeePerGas`.
|
|
782
747
|
tipGasPrice,
|
|
783
748
|
feeData,
|
|
784
|
-
}
|
|
749
|
+
})
|
|
785
750
|
|
|
786
|
-
const { txId } = await asset.baseAsset.api.sendTx(
|
|
751
|
+
const { txId } = await asset.baseAsset.api.sendTx({ asset, walletAccount, unsignedTx })
|
|
787
752
|
|
|
788
753
|
const baseAsset = asset.baseAsset
|
|
789
754
|
if (waitForConfirmation) {
|
package/src/tx-send/tx-send.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseUnsignedTx, updateNonce } from '@exodus/ethereum-lib'
|
|
2
2
|
import { safeString } from '@exodus/safe-string'
|
|
3
3
|
import assert from 'minimalistic-assert'
|
|
4
4
|
|
|
5
5
|
import { getOptimisticTxLogEffects } from '../tx-log/index.js'
|
|
6
|
+
import { signTx } from '../tx-sign/index.js'
|
|
6
7
|
import { ARBITRARY_ADDRESS } from '../tx-type/index.js'
|
|
7
8
|
import { handleBroadcastError } from './broadcast-error-handler.js'
|
|
8
9
|
|
|
@@ -10,16 +11,6 @@ const txSendFactory = ({ assetClientInterface, createTx }) => {
|
|
|
10
11
|
assert(assetClientInterface, 'assetClientInterface is required')
|
|
11
12
|
assert(createTx, 'createTx is required')
|
|
12
13
|
|
|
13
|
-
async function signTx({ asset, unsignedTx, walletAccount }) {
|
|
14
|
-
const { rawTx, txId } = await assetClientInterface.signTransaction({
|
|
15
|
-
assetName: asset.baseAsset.name,
|
|
16
|
-
unsignedTx,
|
|
17
|
-
walletAccount,
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
return { rawTx, txId: normalizeTxId(txId) }
|
|
21
|
-
}
|
|
22
|
-
|
|
23
14
|
return async ({ asset, walletAccount, unsignedTx: providedUnsignedTx, ...legacyParams }) => {
|
|
24
15
|
const baseAsset = asset.baseAsset
|
|
25
16
|
|
|
@@ -41,6 +32,7 @@ const txSendFactory = ({ assetClientInterface, createTx }) => {
|
|
|
41
32
|
// Are there any signin-level errors that should be caught here?
|
|
42
33
|
let { txId, rawTx } = await signTx({
|
|
43
34
|
asset,
|
|
35
|
+
assetClientInterface,
|
|
44
36
|
unsignedTx,
|
|
45
37
|
walletAccount,
|
|
46
38
|
})
|
|
@@ -92,7 +84,12 @@ const txSendFactory = ({ assetClientInterface, createTx }) => {
|
|
|
92
84
|
unsignedTx.txData.nonce = newNonce
|
|
93
85
|
}
|
|
94
86
|
|
|
95
|
-
;({ txId, rawTx } = await signTx({
|
|
87
|
+
;({ txId, rawTx } = await signTx({
|
|
88
|
+
asset,
|
|
89
|
+
assetClientInterface,
|
|
90
|
+
unsignedTx,
|
|
91
|
+
walletAccount,
|
|
92
|
+
}))
|
|
96
93
|
|
|
97
94
|
try {
|
|
98
95
|
await baseAsset.api.broadcastTx(rawTx.toString('hex'))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { normalizeTxId } from '@exodus/ethereum-lib'
|
|
2
|
+
import assert from 'minimalistic-assert'
|
|
3
|
+
|
|
4
|
+
export const signTx = async ({ asset, assetClientInterface, unsignedTx, walletAccount }) => {
|
|
5
|
+
assert(asset, 'expected asset')
|
|
6
|
+
assert(assetClientInterface, 'expected assetClientInterface')
|
|
7
|
+
assert(unsignedTx, 'expected unsignedTx')
|
|
8
|
+
assert(walletAccount, 'expected walletAccount')
|
|
9
|
+
|
|
10
|
+
const { rawTx, txId } = await assetClientInterface.signTransaction({
|
|
11
|
+
assetName: asset.baseAsset.name,
|
|
12
|
+
unsignedTx,
|
|
13
|
+
walletAccount,
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
return { rawTx, txId: normalizeTxId(txId) }
|
|
17
|
+
}
|