@exodus/ethereum-api 8.63.0 → 8.64.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 +22 -0
- package/package.json +3 -3
- package/src/create-asset.js +1 -1
- package/src/eth-like-util.js +1 -2
- package/src/exodus-eth-server/clarity-v2.js +5 -4
- package/src/tx-log/clarity-monitor-v2.js +33 -3
- package/src/tx-log/clarity-monitor.js +36 -3
- package/src/tx-log/ethereum-monitor.js +18 -7
- package/src/tx-log/ethereum-no-history-monitor.js +16 -2
- package/src/tx-log/monitor-utils/get-current-eip7702-delegation.js +39 -0
- package/src/tx-log/monitor-utils/index.js +2 -0
- package/src/tx-log/monitor-utils/verify-pending-tx-status-rpc.js +69 -0
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.64.1](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.64.0...@exodus/ethereum-api@8.64.1) (2026-01-21)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: monitors should check rpc before dropping (#7277)
|
|
13
|
+
|
|
14
|
+
* fix: prevent transactions from being dropped from no history monitor whilst they are still served at the rpc (#7299)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## [8.64.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.63.0...@exodus/ethereum-api@8.64.0) (2026-01-14)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
* feat: EIP delegation status on all monitors (#7193)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
## [8.63.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.62.4...@exodus/ethereum-api@8.63.0) (2026-01-14)
|
|
7
29
|
|
|
8
30
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/ethereum-api",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.64.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",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@exodus/bip44-constants": "^195.0.0",
|
|
30
30
|
"@exodus/crypto": "^1.0.0-rc.26",
|
|
31
31
|
"@exodus/currency": "^6.0.1",
|
|
32
|
-
"@exodus/ethereum-lib": "^5.
|
|
32
|
+
"@exodus/ethereum-lib": "^5.21.0",
|
|
33
33
|
"@exodus/ethereum-meta": "^2.9.1",
|
|
34
34
|
"@exodus/ethereumholesky-meta": "^2.0.5",
|
|
35
35
|
"@exodus/ethereumjs": "^1.8.0",
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"type": "git",
|
|
68
68
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "d828ba4e4dc9f986cfa563653101410e6e81685a"
|
|
71
71
|
}
|
package/src/create-asset.js
CHANGED
|
@@ -303,7 +303,7 @@ export const createAssetFactory = ({
|
|
|
303
303
|
broadcastPrivateBundle,
|
|
304
304
|
broadcastPrivateTx,
|
|
305
305
|
forceGasLimitEstimation,
|
|
306
|
-
getEIP7702Delegation: (addr) => getEIP7702Delegation({
|
|
306
|
+
getEIP7702Delegation: (addr) => getEIP7702Delegation({ address: addr, server }),
|
|
307
307
|
getNonce,
|
|
308
308
|
privacyServer,
|
|
309
309
|
server,
|
package/src/eth-like-util.js
CHANGED
|
@@ -180,8 +180,7 @@ export const getERC20Params = async ({ asset, address, paramNames = DEFAULT_PARA
|
|
|
180
180
|
return response
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
export async function getEIP7702Delegation({
|
|
184
|
-
const server = getServer(asset)
|
|
183
|
+
export async function getEIP7702Delegation({ address, server }) {
|
|
185
184
|
const code = await server.getCode(address)
|
|
186
185
|
|
|
187
186
|
// No code at all
|
|
@@ -175,11 +175,12 @@ export default class ClarityServerV2 extends ClarityServer {
|
|
|
175
175
|
const newCursor = Buffer.alloc(8)
|
|
176
176
|
newCursor.writeBigUInt64LE(BigInt(blockNumber), 0)
|
|
177
177
|
|
|
178
|
+
// Separate confirmed (has blockNumber) from pending (blockNumber is null)
|
|
179
|
+
const confirmed = transactions.filter((tx) => tx.blockNumber != null)
|
|
180
|
+
const pending = transactions.filter((tx) => tx.blockNumber == null)
|
|
181
|
+
|
|
178
182
|
return {
|
|
179
|
-
transactions: {
|
|
180
|
-
confirmed: transactions,
|
|
181
|
-
pending: [],
|
|
182
|
-
},
|
|
183
|
+
transactions: { confirmed, pending },
|
|
183
184
|
cursor: newCursor,
|
|
184
185
|
}
|
|
185
186
|
}
|
|
@@ -10,8 +10,10 @@ import {
|
|
|
10
10
|
checkPendingTransactions,
|
|
11
11
|
excludeUnchangedTokenBalances,
|
|
12
12
|
getAllLogItemsByAsset,
|
|
13
|
+
getCurrentEIP7702Delegation,
|
|
13
14
|
getDeriveDataNeededForTick,
|
|
14
15
|
getDeriveTransactionsToCheck,
|
|
16
|
+
verifyRpcPendingTxStatusBatch,
|
|
15
17
|
} from './monitor-utils/index.js'
|
|
16
18
|
|
|
17
19
|
const { isEmpty } = lodash
|
|
@@ -126,9 +128,26 @@ export class ClarityMonitorV2 extends BaseMonitor {
|
|
|
126
128
|
}
|
|
127
129
|
}
|
|
128
130
|
|
|
131
|
+
// Batch verify all pending txs with a single RPC call (skip if refresh)
|
|
132
|
+
const txIds = Object.keys(pendingTransactionsToCheck)
|
|
133
|
+
const statuses = params.refresh
|
|
134
|
+
? {}
|
|
135
|
+
: await verifyRpcPendingTxStatusBatch({
|
|
136
|
+
baseAsset: this.asset,
|
|
137
|
+
logger: this.logger,
|
|
138
|
+
txIds,
|
|
139
|
+
})
|
|
140
|
+
|
|
129
141
|
for (const { tx, assetName } of Object.values(pendingTransactionsToCheck)) {
|
|
130
|
-
if (params.refresh)
|
|
131
|
-
|
|
142
|
+
if (params.refresh) {
|
|
143
|
+
await updateTx(tx, assetName, { remove: true })
|
|
144
|
+
} else {
|
|
145
|
+
const txStatus = statuses[tx.txId]
|
|
146
|
+
if (txStatus?.status === 'dropped') {
|
|
147
|
+
await updateTx(tx, assetName, { error: 'Dropped' })
|
|
148
|
+
}
|
|
149
|
+
// status === 'confirmed' or 'pending' - tx is fine, wait for Clarity to confirm
|
|
150
|
+
}
|
|
132
151
|
}
|
|
133
152
|
|
|
134
153
|
return { txsToRemove }
|
|
@@ -199,6 +218,13 @@ export class ClarityMonitorV2 extends BaseMonitor {
|
|
|
199
218
|
ourWalletAddress: derivedData.ourWalletAddress,
|
|
200
219
|
})
|
|
201
220
|
|
|
221
|
+
const eip7702Delegation = await getCurrentEIP7702Delegation({
|
|
222
|
+
server: this.server,
|
|
223
|
+
address: derivedData.ourWalletAddress,
|
|
224
|
+
currentDelegation: derivedData.currentAccountState?.eip7702Delegation,
|
|
225
|
+
logger: this.logger,
|
|
226
|
+
})
|
|
227
|
+
|
|
202
228
|
const batch = this.aci.createOperationsBatch()
|
|
203
229
|
|
|
204
230
|
this.aci.removeTxLogBatch({
|
|
@@ -218,7 +244,11 @@ export class ClarityMonitorV2 extends BaseMonitor {
|
|
|
218
244
|
})
|
|
219
245
|
}
|
|
220
246
|
|
|
221
|
-
|
|
247
|
+
// All updates must go through newData (accountState param is only used for mem merging)
|
|
248
|
+
const newData = {
|
|
249
|
+
...accountState,
|
|
250
|
+
...(eip7702Delegation && { eip7702Delegation }),
|
|
251
|
+
}
|
|
222
252
|
|
|
223
253
|
if (cursor) {
|
|
224
254
|
newData.clarityCursor = cursor
|
|
@@ -10,8 +10,10 @@ import {
|
|
|
10
10
|
checkPendingTransactions,
|
|
11
11
|
excludeUnchangedTokenBalances,
|
|
12
12
|
getAllLogItemsByAsset,
|
|
13
|
+
getCurrentEIP7702Delegation,
|
|
13
14
|
getDeriveDataNeededForTick,
|
|
14
15
|
getDeriveTransactionsToCheck,
|
|
16
|
+
verifyRpcPendingTxStatusBatch,
|
|
15
17
|
} from './monitor-utils/index.js'
|
|
16
18
|
|
|
17
19
|
const { isEmpty } = lodash
|
|
@@ -110,9 +112,26 @@ export class ClarityMonitor extends BaseMonitor {
|
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
// Batch verify all pending txs with a single RPC call (skip if refresh)
|
|
116
|
+
const txIds = Object.keys(pendingTransactionsToCheck)
|
|
117
|
+
const statuses = params.refresh
|
|
118
|
+
? {}
|
|
119
|
+
: await verifyRpcPendingTxStatusBatch({
|
|
120
|
+
baseAsset: this.asset,
|
|
121
|
+
logger: this.logger,
|
|
122
|
+
txIds,
|
|
123
|
+
})
|
|
124
|
+
|
|
113
125
|
for (const { tx, assetName } of Object.values(pendingTransactionsToCheck)) {
|
|
114
|
-
if (params.refresh)
|
|
115
|
-
|
|
126
|
+
if (params.refresh) {
|
|
127
|
+
await updateTx(tx, assetName, { remove: true })
|
|
128
|
+
} else {
|
|
129
|
+
const txStatus = statuses[tx.txId]
|
|
130
|
+
if (txStatus?.status === 'dropped') {
|
|
131
|
+
await updateTx(tx, assetName, { error: 'Dropped' })
|
|
132
|
+
}
|
|
133
|
+
// status === 'confirmed' or 'pending' - tx is fine, wait for Clarity to confirm
|
|
134
|
+
}
|
|
116
135
|
}
|
|
117
136
|
|
|
118
137
|
return { txsToRemove }
|
|
@@ -159,6 +178,13 @@ export class ClarityMonitor extends BaseMonitor {
|
|
|
159
178
|
ourWalletAddress: derivedData.ourWalletAddress,
|
|
160
179
|
})
|
|
161
180
|
|
|
181
|
+
const eip7702Delegation = await getCurrentEIP7702Delegation({
|
|
182
|
+
server: this.server,
|
|
183
|
+
address: derivedData.ourWalletAddress,
|
|
184
|
+
currentDelegation: derivedData.currentAccountState?.eip7702Delegation,
|
|
185
|
+
logger: this.logger,
|
|
186
|
+
})
|
|
187
|
+
|
|
162
188
|
const batch = this.aci.createOperationsBatch()
|
|
163
189
|
|
|
164
190
|
this.aci.removeTxLogBatch({
|
|
@@ -178,11 +204,18 @@ export class ClarityMonitor extends BaseMonitor {
|
|
|
178
204
|
})
|
|
179
205
|
}
|
|
180
206
|
|
|
207
|
+
// All updates must go through newData (accountState param is only used for mem merging)
|
|
208
|
+
const newData = {
|
|
209
|
+
...accountState,
|
|
210
|
+
clarityCursor: response.cursor,
|
|
211
|
+
...(eip7702Delegation && { eip7702Delegation }),
|
|
212
|
+
}
|
|
213
|
+
|
|
181
214
|
this.aci.updateAccountStateBatch({
|
|
182
215
|
assetName,
|
|
183
216
|
walletAccount,
|
|
184
217
|
accountState,
|
|
185
|
-
newData
|
|
218
|
+
newData,
|
|
186
219
|
batch,
|
|
187
220
|
})
|
|
188
221
|
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
getDeriveTransactionsToCheck,
|
|
13
13
|
getHistoryFromServer,
|
|
14
14
|
getLogItemsFromServerTx,
|
|
15
|
+
verifyRpcPendingTxStatusBatch,
|
|
15
16
|
} from './monitor-utils/index.js'
|
|
16
17
|
import {
|
|
17
18
|
enableWSUpdates,
|
|
@@ -118,17 +119,27 @@ export class EthereumMonitor extends BaseMonitor {
|
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
// Batch verify all pending txs with a single RPC call (skip if refresh)
|
|
123
|
+
const txIds = Object.keys(pendingTransactionsToCheck)
|
|
124
|
+
const statuses = params.refresh
|
|
125
|
+
? {}
|
|
126
|
+
: await verifyRpcPendingTxStatusBatch({
|
|
127
|
+
baseAsset: this.asset,
|
|
128
|
+
logger: this.logger,
|
|
129
|
+
txIds,
|
|
130
|
+
})
|
|
131
|
+
|
|
121
132
|
for (const { tx, assetName } of Object.values(pendingTransactionsToCheck)) {
|
|
122
133
|
if (params.refresh) {
|
|
123
134
|
await updateTx(tx, assetName, { remove: true })
|
|
124
135
|
} else {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
136
|
+
const txStatus = statuses[tx.txId]
|
|
137
|
+
if (txStatus?.status === 'confirmed') {
|
|
138
|
+
await updateTx(tx, assetName, { isTxConfirmed: true })
|
|
139
|
+
} else if (txStatus?.status === 'dropped') {
|
|
140
|
+
await updateTx(tx, assetName, { isTxConfirmed: false })
|
|
141
|
+
}
|
|
142
|
+
// status === 'pending' or missing - tx still in mempool, do nothing
|
|
132
143
|
}
|
|
133
144
|
}
|
|
134
145
|
|
|
@@ -7,6 +7,7 @@ import { fromHexToString } from '../number-utils.js'
|
|
|
7
7
|
import { UNCONFIRMED_TX_LIMIT } from './monitor-utils/get-derive-transactions-to-check.js'
|
|
8
8
|
import {
|
|
9
9
|
excludeUnchangedTokenBalances,
|
|
10
|
+
getCurrentEIP7702Delegation,
|
|
10
11
|
getDeriveDataNeededForTick,
|
|
11
12
|
getDeriveTransactionsToCheck,
|
|
12
13
|
} from './monitor-utils/index.js'
|
|
@@ -134,7 +135,7 @@ export class EthereumNoHistoryMonitor extends BaseMonitor {
|
|
|
134
135
|
for (const { tx, assetName } of pendingTransactions) {
|
|
135
136
|
const txFromNode = pendingTxsFromNode[tx.txId]
|
|
136
137
|
const isConfirmed = Boolean(txFromNode?.blockHash)
|
|
137
|
-
if (now - tx.date.getTime() > UNCONFIRMED_TX_LIMIT && !
|
|
138
|
+
if (now - tx.date.getTime() > UNCONFIRMED_TX_LIMIT && !txFromNode) {
|
|
138
139
|
txsToRemove.push({
|
|
139
140
|
tx,
|
|
140
141
|
assetSource: { asset: assetName, walletAccount },
|
|
@@ -186,7 +187,20 @@ export class EthereumNoHistoryMonitor extends BaseMonitor {
|
|
|
186
187
|
ourWalletAddress,
|
|
187
188
|
})
|
|
188
189
|
|
|
189
|
-
await
|
|
190
|
+
const eip7702Delegation = await getCurrentEIP7702Delegation({
|
|
191
|
+
server: this.server,
|
|
192
|
+
address: ourWalletAddress,
|
|
193
|
+
currentDelegation: currentAccountState?.eip7702Delegation,
|
|
194
|
+
logger: this.logger,
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
// All updates must go through newData (accountState param is only used for mem merging)
|
|
198
|
+
const newData = {
|
|
199
|
+
...accountState,
|
|
200
|
+
...(eip7702Delegation && { eip7702Delegation }),
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
await this.updateAccountState({ accountState, newData, walletAccount })
|
|
190
204
|
|
|
191
205
|
await this.removeFromTxLog(txsToRemove)
|
|
192
206
|
await this.updateTxLogByAsset({ logItemsByAsset, walletAccount, refresh })
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { getEIP7702Delegation } from '../../eth-like-util.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if the address has an EIP-7702 delegation and returns the delegation state.
|
|
5
|
+
* Returns the new state if changed, or the current state if unchanged.
|
|
6
|
+
* On error, returns the current state to preserve existing data.
|
|
7
|
+
*
|
|
8
|
+
* @param {Object} params
|
|
9
|
+
* @param {Object} params.server - The server instance to use for getCode
|
|
10
|
+
* @param {string} params.address - The wallet address to check
|
|
11
|
+
* @param {Object} [params.currentDelegation] - The current delegation state from accountState
|
|
12
|
+
* @param {Object} [params.logger] - Optional logger for warnings
|
|
13
|
+
* @returns {Promise<Object|undefined>} The delegation state to use
|
|
14
|
+
*/
|
|
15
|
+
export async function getCurrentEIP7702Delegation({ server, address, currentDelegation, logger }) {
|
|
16
|
+
try {
|
|
17
|
+
const result = await getEIP7702Delegation({ address, server })
|
|
18
|
+
|
|
19
|
+
// Return new state if changed
|
|
20
|
+
if (
|
|
21
|
+
currentDelegation?.isDelegated !== result.isDelegated ||
|
|
22
|
+
currentDelegation?.delegatedAddress !== result.delegatedAddress
|
|
23
|
+
) {
|
|
24
|
+
return {
|
|
25
|
+
isDelegated: result.isDelegated,
|
|
26
|
+
delegatedAddress: result.delegatedAddress,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (logger) {
|
|
31
|
+
logger.warn('Failed to check EIP-7702 delegation:', error)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Return current state if unchanged or on error
|
|
36
|
+
return currentDelegation
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default getCurrentEIP7702Delegation
|
|
@@ -5,4 +5,6 @@ export { default as getLogItemsFromServerTx } from './get-log-items-from-server-
|
|
|
5
5
|
export { default as getHistoryFromServer } from './get-history-from-server.js'
|
|
6
6
|
export { default as checkPendingTransactions } from './check-pending-transactions.js'
|
|
7
7
|
export { default as getDeriveTransactionsToCheck } from './get-derive-transactions-to-check.js'
|
|
8
|
+
export { default as getCurrentEIP7702Delegation } from './get-current-eip7702-delegation.js'
|
|
9
|
+
export { default as verifyRpcPendingTxStatusBatch } from './verify-pending-tx-status-rpc.js'
|
|
8
10
|
export * from './exclude-unchanged-token-balances.js'
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determines the status of an RPC transaction response.
|
|
3
|
+
*
|
|
4
|
+
* @param {Object|null} rpcTx - The RPC transaction response
|
|
5
|
+
* @returns {{status: 'confirmed' | 'pending' | 'dropped', blockNumber?: number}}
|
|
6
|
+
*/
|
|
7
|
+
function getTxStatus(rpcTx) {
|
|
8
|
+
if (rpcTx?.blockNumber) {
|
|
9
|
+
return { status: 'confirmed', blockNumber: parseInt(rpcTx.blockNumber, 16) }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (rpcTx) {
|
|
13
|
+
return { status: 'pending' }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return { status: 'dropped' }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Batch verify pending transactions against the RPC node before marking them as dropped.
|
|
21
|
+
*
|
|
22
|
+
* Any lag in the Clarity indexer can cause confirmed transactions to be incorrectly
|
|
23
|
+
* flagged as dropped if Clarity hasn't indexed their block yet.
|
|
24
|
+
* By checking the RPC directly, we avoid this race condition.
|
|
25
|
+
*
|
|
26
|
+
* Uses a single batch RPC call for efficiency and graceful error handling.
|
|
27
|
+
*
|
|
28
|
+
* @param {Object} params
|
|
29
|
+
* @param {Object} params.baseAsset - The base asset to get the server from
|
|
30
|
+
* @param {Object} params.logger - Logger instance for info/debug output
|
|
31
|
+
* @param {string[]} params.txIds - Array of transaction IDs/hashes to verify
|
|
32
|
+
* @returns {Promise<Object<string, {status: 'confirmed' | 'pending' | 'dropped', blockNumber?: number}>>}
|
|
33
|
+
*/
|
|
34
|
+
export default async function verifyRpcPendingTxStatusBatch({ baseAsset, logger, txIds }) {
|
|
35
|
+
if (txIds.length === 0) return {}
|
|
36
|
+
|
|
37
|
+
const server = baseAsset.server
|
|
38
|
+
|
|
39
|
+
// Build batch request
|
|
40
|
+
const requests = txIds.map((txId) => server.getTransactionByHashRequest(txId))
|
|
41
|
+
|
|
42
|
+
let responses
|
|
43
|
+
try {
|
|
44
|
+
responses = await server.sendBatchRequest(requests)
|
|
45
|
+
} catch (error) {
|
|
46
|
+
// If batch request fails, skip all drop checks (safe default)
|
|
47
|
+
logger.warn('Batch RPC request failed, skipping drop checks', error)
|
|
48
|
+
return {}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Map responses to statuses
|
|
52
|
+
const results = {}
|
|
53
|
+
txIds.forEach((txId, idx) => {
|
|
54
|
+
const rpcTx = responses[idx]
|
|
55
|
+
const txStatus = getTxStatus(rpcTx)
|
|
56
|
+
results[txId] = txStatus
|
|
57
|
+
|
|
58
|
+
// Log each tx status
|
|
59
|
+
if (txStatus.status === 'confirmed') {
|
|
60
|
+
logger.info(`tx ${txId} is confirmed on-chain (block ${txStatus.blockNumber}), skipping drop`)
|
|
61
|
+
} else if (txStatus.status === 'pending') {
|
|
62
|
+
logger.info(`tx ${txId} is still in mempool, skipping drop`)
|
|
63
|
+
} else {
|
|
64
|
+
logger.info(`tx ${txId} not found on-chain, marking as dropped`)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
return results
|
|
69
|
+
}
|