@exodus/ethereum-api 8.64.6 → 8.65.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/package.json +5 -4
- package/src/create-asset-utils.js +4 -0
- package/src/create-asset.js +3 -0
- package/src/ens/index.js +1 -0
- package/src/error-wrapper.js +298 -16
- package/src/eth-like-util.js +74 -31
- package/src/exodus-eth-server/api-coin-nodes.js +2 -1
- package/src/exodus-eth-server/clarity-v2.js +25 -7
- package/src/exodus-eth-server/clarity.js +49 -2
- package/src/exodus-eth-server/index.js +1 -1
- package/src/fee-utils.js +32 -30
- package/src/index.js +7 -1
- package/src/nft-utils.js +6 -4
- package/src/optimism-gas/index.js +8 -1
- package/src/staking/ethereum/api.js +8 -1
- package/src/staking/matic/api.js +8 -1
- package/src/tx-log/clarity-monitor-v2.js +10 -1
- package/src/tx-log/clarity-monitor.js +3 -1
- package/src/tx-log/ethereum-no-history-monitor.js +3 -1
- package/src/tx-log/monitor-utils/get-current-eip7702-delegation.js +40 -10
- package/src/tx-send/broadcast-error-handler.js +58 -0
- package/src/tx-send/tx-send.js +22 -61
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { retry } from '@exodus/simple-retry'
|
|
2
|
+
import { TraceId } from '@exodus/traceparent'
|
|
2
3
|
import assert from 'minimalistic-assert'
|
|
3
4
|
|
|
4
5
|
import ClarityServer, { RPC_REQUEST_TIMEOUT } from './clarity.js'
|
|
@@ -43,14 +44,31 @@ const fetchJson = async (url, fetchOptions) => {
|
|
|
43
44
|
const response = await fetch(url, fetchOptions)
|
|
44
45
|
|
|
45
46
|
if (!response.ok) {
|
|
46
|
-
|
|
47
|
+
const traceId = TraceId.fromResponse(response)
|
|
48
|
+
const error = new Error(
|
|
47
49
|
`${url} returned ${response.status}: ${
|
|
48
50
|
response.statusText || 'Unknown Status Text'
|
|
49
51
|
}. Body: ${await getTextFromResponse(response)}`
|
|
50
52
|
)
|
|
53
|
+
if (traceId) {
|
|
54
|
+
error.traceId = traceId
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
throw error
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const json = await response.json()
|
|
61
|
+
|
|
62
|
+
// Only capture trace ID if there's an RPC error in the response
|
|
63
|
+
// (handleJsonRPCResponse will extract it when throwing the error)
|
|
64
|
+
if (json.error) {
|
|
65
|
+
const traceId = TraceId.fromResponse(response)
|
|
66
|
+
if (traceId) {
|
|
67
|
+
json.__traceId = traceId
|
|
68
|
+
}
|
|
51
69
|
}
|
|
52
70
|
|
|
53
|
-
return
|
|
71
|
+
return json
|
|
54
72
|
}
|
|
55
73
|
|
|
56
74
|
async function fetchJsonRetry(url, fetchOptions) {
|
|
@@ -126,9 +144,6 @@ export default class ClarityServerV2 extends ClarityServer {
|
|
|
126
144
|
// See: https://github.com/ExodusMovement/clarity/blob/d3c2a7f501a4391da630592bca3bf57c3ddd5e89/src/modules/ethereum-like/gas-price/index.js#L192C5-L219C6
|
|
127
145
|
return await this.getGasPriceEstimation()
|
|
128
146
|
} catch {
|
|
129
|
-
console.log(
|
|
130
|
-
`failed to query ${this.baseAssetName} gas-price-estimation endpoint, falling back to websocket`
|
|
131
|
-
)
|
|
132
147
|
// HACK: The `getGasPriceEstimation` endpoint is not guaranteed
|
|
133
148
|
// to exist for all assets. In this case, we'll fallback
|
|
134
149
|
// to legacy behaviour, which is to query via the WebSocket.
|
|
@@ -185,8 +200,9 @@ export default class ClarityServerV2 extends ClarityServer {
|
|
|
185
200
|
}
|
|
186
201
|
}
|
|
187
202
|
|
|
188
|
-
fetchRpcHttpRequest = ({ baseApiPath, body }) =>
|
|
189
|
-
fetchHttpRequest({ baseApiPath, path: '/rpc', method: 'POST', body })
|
|
203
|
+
fetchRpcHttpRequest = ({ baseApiPath, body }) => {
|
|
204
|
+
return fetchHttpRequest({ baseApiPath, path: '/rpc', method: 'POST', body })
|
|
205
|
+
}
|
|
190
206
|
|
|
191
207
|
async sendRpcRequest(rpcRequest) {
|
|
192
208
|
try {
|
|
@@ -201,6 +217,8 @@ export default class ClarityServerV2 extends ClarityServer {
|
|
|
201
217
|
}
|
|
202
218
|
}
|
|
203
219
|
|
|
220
|
+
// Maybe some functions from clarity should be overriden to have handleJsonRPCResponse as well
|
|
221
|
+
|
|
204
222
|
async sendRawTransaction(...params) {
|
|
205
223
|
const { baseApiPath } = this
|
|
206
224
|
const request = this.sendRawTransactionRequest(...params)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { bufferToHex } from '@exodus/ethereumjs/util'
|
|
2
2
|
import { safeString } from '@exodus/safe-string'
|
|
3
3
|
import SolidityContract from '@exodus/solidity-contract'
|
|
4
|
+
import { TraceId } from '@exodus/traceparent'
|
|
4
5
|
import EventEmitter from 'events/events.js'
|
|
5
6
|
import io from 'socket.io-client'
|
|
6
7
|
|
|
@@ -104,12 +105,20 @@ export default class ClarityServer extends EventEmitter {
|
|
|
104
105
|
|
|
105
106
|
const revisedError = new Error(`Bad rpc response: ${message}`)
|
|
106
107
|
revisedError.hint = safeString`Bad rpc response: ${errorMessageToSafeHint(message)}`
|
|
108
|
+
|
|
109
|
+
// Preserve trace ID: from HTTP (__traceId) or WebSocket (traceparent in JSON body)
|
|
110
|
+
const traceId = response?.__traceId || response?.traceparent
|
|
111
|
+
if (traceId) {
|
|
112
|
+
revisedError.traceId = traceId
|
|
113
|
+
}
|
|
114
|
+
|
|
107
115
|
throw revisedError
|
|
108
116
|
}
|
|
109
117
|
|
|
110
118
|
return result
|
|
111
119
|
}
|
|
112
120
|
|
|
121
|
+
// Transport: WS only in ClarityServer, HTTP only in ClarityServerV2 (overridden)
|
|
113
122
|
async getAllTransactions(params) {
|
|
114
123
|
const transactions = { pending: [], confirmed: [] }
|
|
115
124
|
const cursor = await this.getTransactions({
|
|
@@ -129,6 +138,7 @@ export default class ClarityServer extends EventEmitter {
|
|
|
129
138
|
return { cursor, transactions }
|
|
130
139
|
}
|
|
131
140
|
|
|
141
|
+
// Transport: WS only (uses transactions socket, not RPC socket)
|
|
132
142
|
async getTransactions({ walletAccount, address, cursor, onChunk }) {
|
|
133
143
|
const socket = this.connectTransactions({ walletAccount, address })
|
|
134
144
|
const listener = (isPending, chunk, callback) => {
|
|
@@ -149,6 +159,7 @@ export default class ClarityServer extends EventEmitter {
|
|
|
149
159
|
.finally(() => socket.off('transactionsChunk', listener))
|
|
150
160
|
}
|
|
151
161
|
|
|
162
|
+
// Transport: WS only (uses fee socket)
|
|
152
163
|
getFeeFromWebSocket() {
|
|
153
164
|
const socket = this.connectFee()
|
|
154
165
|
return new Promise((resolve, reject) => {
|
|
@@ -165,10 +176,12 @@ export default class ClarityServer extends EventEmitter {
|
|
|
165
176
|
})
|
|
166
177
|
}
|
|
167
178
|
|
|
179
|
+
// Transport: WS only in ClarityServer, HTTP first → WS fallback in ClarityServerV2 (overridden)
|
|
168
180
|
async getFee() {
|
|
169
181
|
return this.getFeeFromWebSocket()
|
|
170
182
|
}
|
|
171
183
|
|
|
184
|
+
// Transport: Depends on getFee() - WS only in ClarityServer, HTTP first → WS fallback in ClarityServerV2
|
|
172
185
|
// for fee monitors
|
|
173
186
|
async getGasPrice() {
|
|
174
187
|
const fee = await this.getFee()
|
|
@@ -185,11 +198,18 @@ export default class ClarityServer extends EventEmitter {
|
|
|
185
198
|
const timeout = setTimeout(() => reject(new Error(RPC_REQUEST_TIMEOUT)), 3000)
|
|
186
199
|
rpcSocket.emit('request', rpcRequest, (response) => {
|
|
187
200
|
clearTimeout(timeout)
|
|
201
|
+
const rawTraceparent = response?.traceparent || response?.[0]?.traceparent
|
|
202
|
+
if (rawTraceparent) {
|
|
203
|
+
// eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only
|
|
204
|
+
response.traceparent = TraceId.fromRawTraceparent(rawTraceparent)
|
|
205
|
+
}
|
|
206
|
+
|
|
188
207
|
resolve(response)
|
|
189
208
|
})
|
|
190
209
|
})
|
|
191
210
|
}
|
|
192
211
|
|
|
212
|
+
// Transport: WS only in ClarityServer, WS first → HTTP fallback in ClarityServerV2
|
|
193
213
|
async sendBatchRequest(batch) {
|
|
194
214
|
const responses = await this.sendRpcRequest(batch)
|
|
195
215
|
// FIXME: this falls apart if responses is not an array
|
|
@@ -206,12 +226,14 @@ export default class ClarityServer extends EventEmitter {
|
|
|
206
226
|
return batch.map((request) => keyed[`${request.id}`])
|
|
207
227
|
}
|
|
208
228
|
|
|
229
|
+
// Transport: Uses sendRpcRequest - WS only in ClarityServer, WS first → HTTP fallback in ClarityServerV2
|
|
209
230
|
async sendRequest(request) {
|
|
210
231
|
const response = await this.sendRpcRequest(request)
|
|
211
232
|
|
|
212
233
|
return this.handleJsonRPCResponse(response)
|
|
213
234
|
}
|
|
214
235
|
|
|
236
|
+
// Transport: Via getCode → sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
215
237
|
async isContract(address) {
|
|
216
238
|
const code = await this.getCode(address)
|
|
217
239
|
return code.length > 2
|
|
@@ -327,11 +349,13 @@ export default class ClarityServer extends EventEmitter {
|
|
|
327
349
|
})
|
|
328
350
|
}
|
|
329
351
|
|
|
352
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
330
353
|
async proxyToCoinNode(params) {
|
|
331
354
|
const request = this.buildRequest(params)
|
|
332
355
|
return this.sendRequest(request)
|
|
333
356
|
}
|
|
334
357
|
|
|
358
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
335
359
|
async balanceOf(address, tokenAddress, tag = 'latest') {
|
|
336
360
|
const request = this.balanceOfRequest(address, tokenAddress, tag)
|
|
337
361
|
const result = await this.sendRequest(request)
|
|
@@ -343,69 +367,83 @@ export default class ClarityServer extends EventEmitter {
|
|
|
343
367
|
}
|
|
344
368
|
}
|
|
345
369
|
|
|
370
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
346
371
|
async getBalance(...params) {
|
|
347
|
-
const request = this.getBalanceRequest(...params)
|
|
372
|
+
const request = this.getBalanceRequest(...params) // eth_getBalance
|
|
348
373
|
return this.sendRequest(request)
|
|
349
374
|
}
|
|
350
375
|
|
|
376
|
+
// Transport: Via getBalance → sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
351
377
|
async getBalanceProxied(...params) {
|
|
352
|
-
return this.getBalance(...params)
|
|
378
|
+
return this.getBalance(...params) // eth_getBalance
|
|
353
379
|
}
|
|
354
380
|
|
|
381
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
355
382
|
async gasPrice(...params) {
|
|
356
383
|
const request = this.gasPriceRequest(...params)
|
|
357
384
|
return this.sendRequest(request)
|
|
358
385
|
}
|
|
359
386
|
|
|
387
|
+
// Transport: WS only in ClarityServer, HTTP only in ClarityServerV2 (overridden)
|
|
360
388
|
async estimateGas(...params) {
|
|
361
389
|
const request = this.estimateGasRequest(...params)
|
|
362
390
|
return this.sendRequest(request)
|
|
363
391
|
}
|
|
364
392
|
|
|
393
|
+
// Transport: WS only in ClarityServer, HTTP only in ClarityServerV2 (overridden)
|
|
365
394
|
async sendRawTransaction(...params) {
|
|
366
395
|
const request = this.sendRawTransactionRequest(...params)
|
|
367
396
|
return this.sendRequest(request)
|
|
368
397
|
}
|
|
369
398
|
|
|
399
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
370
400
|
async getCode(...params) {
|
|
371
401
|
const request = this.getCodeRequest(...params)
|
|
372
402
|
return this.sendRequest(request)
|
|
373
403
|
}
|
|
374
404
|
|
|
405
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
375
406
|
async getStorageAt(...params) {
|
|
376
407
|
const request = this.getStorageAtRequest(...params)
|
|
377
408
|
return this.sendRequest(request)
|
|
378
409
|
}
|
|
379
410
|
|
|
411
|
+
// Transport: WS only in ClarityServer, HTTP only in ClarityServerV2 (overridden)
|
|
380
412
|
async getTransactionCount(...params) {
|
|
381
413
|
const request = this.getTransactionCountRequest(...params)
|
|
382
414
|
return this.sendRequest(request)
|
|
383
415
|
}
|
|
384
416
|
|
|
417
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
385
418
|
async getTransactionByHash(...params) {
|
|
386
419
|
const request = this.getTransactionByHashRequest(...params)
|
|
387
420
|
return this.sendRequest(request)
|
|
388
421
|
}
|
|
389
422
|
|
|
423
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
390
424
|
async getTransactionReceipt(...params) {
|
|
391
425
|
const request = this.getTransactionReceiptRequest(...params)
|
|
392
426
|
return this.sendRequest(request)
|
|
393
427
|
}
|
|
394
428
|
|
|
429
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
395
430
|
async ethCall(...params) {
|
|
396
431
|
const request = this.ethCallRequest(...params)
|
|
397
432
|
return this.sendRequest(request)
|
|
398
433
|
}
|
|
399
434
|
|
|
435
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
400
436
|
async blockNumber(...params) {
|
|
401
437
|
const request = this.blockNumberRequest(...params)
|
|
402
438
|
return this.sendRequest(request)
|
|
403
439
|
}
|
|
404
440
|
|
|
441
|
+
// Transport: Via getBlockByNumber → sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
405
442
|
async getLatestBlock() {
|
|
406
443
|
return this.getBlockByNumber('latest')
|
|
407
444
|
}
|
|
408
445
|
|
|
446
|
+
// Transport: Via getLatestBlock → getBlockByNumber → sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
409
447
|
async getBaseFeePerGas() {
|
|
410
448
|
const response = await this.getLatestBlock()
|
|
411
449
|
if (response.baseFeePerGas) {
|
|
@@ -413,46 +451,55 @@ export default class ClarityServer extends EventEmitter {
|
|
|
413
451
|
}
|
|
414
452
|
}
|
|
415
453
|
|
|
454
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
416
455
|
async getBlockByHash(...params) {
|
|
417
456
|
const request = this.getBlockByHashRequest(...params)
|
|
418
457
|
return this.sendRequest(request)
|
|
419
458
|
}
|
|
420
459
|
|
|
460
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
421
461
|
async getBlockTransactionCountByNumber(...params) {
|
|
422
462
|
const request = this.getBlockTransactionCountByNumberRequest(...params)
|
|
423
463
|
return this.sendRequest(request)
|
|
424
464
|
}
|
|
425
465
|
|
|
466
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
426
467
|
async getBlockByNumber(...params) {
|
|
427
468
|
const request = this.getBlockByNumberRequest(...params)
|
|
428
469
|
return this.sendRequest(request)
|
|
429
470
|
}
|
|
430
471
|
|
|
472
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
431
473
|
async simulateV1(...params) {
|
|
432
474
|
const request = this.simulateV1Request(...params)
|
|
433
475
|
return this.sendRequest(request)
|
|
434
476
|
}
|
|
435
477
|
|
|
478
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
436
479
|
async simulateRawTransaction(...params) {
|
|
437
480
|
const request = this.simulateRawTransactionRequest(...params)
|
|
438
481
|
return this.sendRequest(request)
|
|
439
482
|
}
|
|
440
483
|
|
|
484
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
441
485
|
async getCoinbase() {
|
|
442
486
|
const request = this.coinbaseRequest()
|
|
443
487
|
return this.sendRequest(request)
|
|
444
488
|
}
|
|
445
489
|
|
|
490
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
446
491
|
async getCompilers() {
|
|
447
492
|
const request = this.getCompilersRequest()
|
|
448
493
|
return this.sendRequest(request)
|
|
449
494
|
}
|
|
450
495
|
|
|
496
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
451
497
|
async getNetVersion() {
|
|
452
498
|
const request = this.getNetVersion()
|
|
453
499
|
return this.sendRequest(request)
|
|
454
500
|
}
|
|
455
501
|
|
|
502
|
+
// Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
|
|
456
503
|
async getLogs(...params) {
|
|
457
504
|
const request = this.getLogsRequest(...params)
|
|
458
505
|
return this.sendRequest(request)
|
|
@@ -22,7 +22,7 @@ export function createEvmServer({ assetName, serverUrl, monitorType }) {
|
|
|
22
22
|
assert(monitorType, 'monitorType is required')
|
|
23
23
|
switch (monitorType) {
|
|
24
24
|
case 'no-history':
|
|
25
|
-
return new ApiCoinNodesServer({ uri: serverUrl })
|
|
25
|
+
return new ApiCoinNodesServer({ baseAssetName: assetName, uri: serverUrl })
|
|
26
26
|
case 'clarity':
|
|
27
27
|
return new ClarityServer({ baseAssetName: assetName, uri: serverUrl })
|
|
28
28
|
case 'clarity-v2':
|
package/src/fee-utils.js
CHANGED
|
@@ -1,34 +1,40 @@
|
|
|
1
1
|
import assert from 'minimalistic-assert'
|
|
2
2
|
|
|
3
|
-
export const applyMultiplierToPrice = ({ feeAsset, gasPriceMultiplier, price }) => {
|
|
4
|
-
assert(typeof price === 'string', 'price should be a string')
|
|
5
|
-
return feeAsset.currency
|
|
6
|
-
.parse(price)
|
|
7
|
-
.mul(gasPriceMultiplier || 1)
|
|
8
|
-
.toBaseString({ unit: true })
|
|
9
|
-
}
|
|
10
|
-
|
|
11
3
|
/**
|
|
12
4
|
* Returns augmented `feeConfig` values manipulated using the `feeData`,
|
|
13
5
|
* for example, like multiplying the `gasPrice`. This helps us to apply
|
|
14
6
|
* modifications to values before presenting them to the consumer.
|
|
15
|
-
*
|
|
16
|
-
* TODO: We shouldn't actually do this, lol. The closer we are to
|
|
17
|
-
* the node, the better!
|
|
18
7
|
*/
|
|
19
|
-
export const
|
|
8
|
+
export const refineFeeConfig = ({ feeAsset, feeConfig, gasPriceBump, gasPriceMultiplier }) => {
|
|
9
|
+
const fromString = (str) => {
|
|
10
|
+
assert(typeof str === 'string', 'expected string')
|
|
11
|
+
return feeAsset.currency.parse(str)
|
|
12
|
+
}
|
|
13
|
+
|
|
20
14
|
try {
|
|
21
|
-
const { gasPrice, baseFeePerGas, ...extras } = feeConfig
|
|
15
|
+
const { gasPrice, baseFeePerGas, tipGasPrice, ...extras } = feeConfig
|
|
16
|
+
|
|
17
|
+
gasPriceMultiplier ||= 1
|
|
18
|
+
gasPriceBump ||= feeAsset.currency.ZERO
|
|
19
|
+
|
|
20
|
+
if (!baseFeePerGas) {
|
|
21
|
+
const nextGasPrice = fromString(gasPrice).mul(gasPriceMultiplier).add(gasPriceBump)
|
|
22
|
+
return {
|
|
23
|
+
...extras,
|
|
24
|
+
gasPrice: nextGasPrice.toBaseString({ unit: true }),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const nextBaseFeePerGas = fromString(baseFeePerGas).mul(gasPriceMultiplier)
|
|
29
|
+
const nextTipGasPrice = tipGasPrice
|
|
30
|
+
? fromString(tipGasPrice).mul(gasPriceMultiplier).add(gasPriceBump)
|
|
31
|
+
: gasPriceBump
|
|
32
|
+
|
|
22
33
|
return {
|
|
23
34
|
...extras,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
price: gasPrice,
|
|
28
|
-
}) /* required */,
|
|
29
|
-
baseFeePerGas: baseFeePerGas
|
|
30
|
-
? applyMultiplierToPrice({ feeAsset, gasPriceMultiplier, price: baseFeePerGas })
|
|
31
|
-
: undefined,
|
|
35
|
+
baseFeePerGas: nextBaseFeePerGas.toBaseString({ unit: true }),
|
|
36
|
+
tipGasPrice: nextTipGasPrice.toBaseString({ unit: true }),
|
|
37
|
+
gasPrice: nextBaseFeePerGas.add(nextTipGasPrice).toBaseString({ unit: true }),
|
|
32
38
|
}
|
|
33
39
|
} catch (e) {
|
|
34
40
|
console.error(
|
|
@@ -148,9 +154,10 @@ export const calculateEthLikeFeeMonitorUpdate = async ({
|
|
|
148
154
|
|
|
149
155
|
// Depending on whether `eip1559Enabled` on the client, we
|
|
150
156
|
// can choose to return different properties.
|
|
151
|
-
const { eip1559Enabled, gasPriceMultiplier } =
|
|
152
|
-
|
|
153
|
-
|
|
157
|
+
const { eip1559Enabled, gasPriceBump, gasPriceMultiplier } =
|
|
158
|
+
await assetClientInterface.getFeeConfig({
|
|
159
|
+
assetName: feeAsset.name,
|
|
160
|
+
})
|
|
154
161
|
|
|
155
162
|
// NOTE: The `gasPrice` is a required value for all EVM networks.
|
|
156
163
|
const gasPrice = ensureBigInt(fetchedGasPrices.gasPrice)
|
|
@@ -159,12 +166,7 @@ export const calculateEthLikeFeeMonitorUpdate = async ({
|
|
|
159
166
|
? calculateEthLikeFeeMonitorUpdateEip1559({ gasPrice, feeAsset, fetchedGasPrices })
|
|
160
167
|
: calculateEthLikeFeeMonitorUpdateNonEip1559({ gasPrice }))
|
|
161
168
|
|
|
162
|
-
|
|
163
|
-
// to our `gasPrice` and `baseFeePerGas` values. Once we're
|
|
164
|
-
// feeling confident, we should be safe to skip doing this for
|
|
165
|
-
// `eip1559Enabled` chains, since we should be able to guarantee
|
|
166
|
-
// next block inclusion with accuracy.
|
|
167
|
-
return rewriteFeeConfig({ feeAsset, feeConfig, gasPriceMultiplier })
|
|
169
|
+
return refineFeeConfig({ feeAsset, feeConfig, gasPriceBump, gasPriceMultiplier })
|
|
168
170
|
}
|
|
169
171
|
|
|
170
172
|
/**
|
package/src/index.js
CHANGED
|
@@ -88,7 +88,13 @@ export {
|
|
|
88
88
|
fromHexToBN,
|
|
89
89
|
} from './number-utils.js'
|
|
90
90
|
|
|
91
|
-
export {
|
|
91
|
+
export {
|
|
92
|
+
EVM_ERROR_REASONS,
|
|
93
|
+
EVM_ERROR_TYPES,
|
|
94
|
+
getEvmErrorReason,
|
|
95
|
+
withErrorReason,
|
|
96
|
+
EthLikeError,
|
|
97
|
+
} from './error-wrapper.js'
|
|
92
98
|
|
|
93
99
|
export { txSendFactory } from './tx-send/index.js'
|
|
94
100
|
|
package/src/nft-utils.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { safeString } from '@exodus/safe-string'
|
|
1
2
|
import SolidityContract from '@exodus/solidity-contract'
|
|
2
3
|
import assert from 'minimalistic-assert'
|
|
3
4
|
|
|
4
|
-
import
|
|
5
|
+
import { EthLikeError, EVM_ERROR_REASONS } from './error-wrapper.js'
|
|
5
6
|
import { fetchGasLimit } from './gas-estimation.js'
|
|
6
7
|
|
|
7
8
|
export const getNftArguments = async ({ asset, nft, fromAddress, toAddress }) => {
|
|
@@ -44,10 +45,11 @@ export const getNftArguments = async ({ asset, nft, fromAddress, toAddress }) =>
|
|
|
44
45
|
}
|
|
45
46
|
})
|
|
46
47
|
).catch((e) => {
|
|
47
|
-
throw new
|
|
48
|
+
throw new EthLikeError({
|
|
48
49
|
message: errors.join('\n'),
|
|
49
|
-
|
|
50
|
-
hint:
|
|
50
|
+
errorReasonInfo: EVM_ERROR_REASONS.fetchGasLimitFailed,
|
|
51
|
+
hint: safeString`getNftArguments`,
|
|
52
|
+
traceId: e.traceId,
|
|
51
53
|
})
|
|
52
54
|
})
|
|
53
55
|
return {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createContract, createEthereumJsTx } from '@exodus/ethereum-lib'
|
|
2
2
|
import { bufferToHex } from '@exodus/ethereumjs/util'
|
|
3
|
+
import { safeString } from '@exodus/safe-string'
|
|
3
4
|
import assert from 'minimalistic-assert'
|
|
4
5
|
|
|
6
|
+
import { EVM_ERROR_REASONS, withErrorReason } from '../error-wrapper.js'
|
|
5
7
|
import { fromHexToBigInt } from '../number-utils.js'
|
|
6
8
|
|
|
7
9
|
export const estimateL1DataFeeFactory = ({ l1GasOracleAddress, server }) => {
|
|
@@ -14,7 +16,12 @@ export const estimateL1DataFeeFactory = ({ l1GasOracleAddress, server }) => {
|
|
|
14
16
|
const callData = gasContract.getL1Fee.build(serialized)
|
|
15
17
|
const buffer = Buffer.from(callData)
|
|
16
18
|
const data = bufferToHex(buffer)
|
|
17
|
-
const hex = await
|
|
19
|
+
const hex = await withErrorReason({
|
|
20
|
+
promise: server.ethCall({ to: l1GasOracleAddress, data }, 'latest'),
|
|
21
|
+
errorReasonInfo: EVM_ERROR_REASONS.ethCallFailed,
|
|
22
|
+
hint: safeString`estimateL1DataFee`,
|
|
23
|
+
baseAssetName: server.baseAssetName,
|
|
24
|
+
})
|
|
18
25
|
const l1DataFee = fromHexToBigInt(hex)
|
|
19
26
|
const padFee = l1DataFee / BigInt(4)
|
|
20
27
|
const maxL1DataFee = l1DataFee + padFee
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createContract } from '@exodus/ethereum-lib'
|
|
2
2
|
import { bufferToHex } from '@exodus/ethereumjs/util'
|
|
3
|
+
import { safeString } from '@exodus/safe-string'
|
|
3
4
|
import { retry } from '@exodus/simple-retry'
|
|
4
5
|
|
|
6
|
+
import { EVM_ERROR_REASONS, withErrorReason } from '../../error-wrapper.js'
|
|
5
7
|
import { getServerByName } from '../../exodus-eth-server/index.js'
|
|
6
8
|
|
|
7
9
|
// TODO: Shouldn't this be a function of `ethereumStakingState.minDelegateAmount`?
|
|
@@ -78,7 +80,12 @@ export class EthereumStaking {
|
|
|
78
80
|
if (typeof from === 'string' && from.length > 0) data.from = from
|
|
79
81
|
|
|
80
82
|
const eth = this.server || getServerByName(this.asset.name)
|
|
81
|
-
return
|
|
83
|
+
return withErrorReason({
|
|
84
|
+
promise: retry((...args) => eth.ethCall(...args), { delayTimesMs: RETRY_DELAYS })(data),
|
|
85
|
+
errorReasonInfo: EVM_ERROR_REASONS.ethCallFailed,
|
|
86
|
+
hint: safeString`stakingEthReadFunctionContract`,
|
|
87
|
+
baseAssetName: eth.baseAssetName,
|
|
88
|
+
})
|
|
82
89
|
}
|
|
83
90
|
|
|
84
91
|
// === ACCOUNTING ===
|
package/src/staking/matic/api.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { createContract } from '@exodus/ethereum-lib'
|
|
2
2
|
import ethAssets from '@exodus/ethereum-meta'
|
|
3
3
|
import { bufferToHex } from '@exodus/ethereumjs/util'
|
|
4
|
+
import { safeString } from '@exodus/safe-string'
|
|
4
5
|
import { retry } from '@exodus/simple-retry'
|
|
5
6
|
import BN from 'bn.js'
|
|
6
7
|
|
|
8
|
+
import { EVM_ERROR_REASONS, withErrorReason } from '../../error-wrapper.js'
|
|
7
9
|
import { getServerByName } from '../../exodus-eth-server/index.js'
|
|
8
10
|
import { fromHexToBN, fromHexToString, splitIn32BytesArray } from '../../number-utils.js'
|
|
9
11
|
|
|
@@ -43,7 +45,12 @@ export class MaticStakingApi {
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
const eth = this.server || getServerByName('ethereum')
|
|
46
|
-
return
|
|
48
|
+
return withErrorReason({
|
|
49
|
+
promise: retry((...args) => eth.ethCall(...args), { delayTimesMs: RETRY_DELAYS })(data),
|
|
50
|
+
errorReasonInfo: EVM_ERROR_REASONS.ethCallFailed,
|
|
51
|
+
hint: safeString`stakingMaticReadFunctionContract`,
|
|
52
|
+
baseAssetName: eth.baseAssetName,
|
|
53
|
+
})
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
getWithdrawalDelay = async () => {
|
|
@@ -28,7 +28,14 @@ export class ClarityMonitorV2 extends BaseMonitor {
|
|
|
28
28
|
#walletAccountByAddress = new Map()
|
|
29
29
|
#walletAccountInfo = new Map()
|
|
30
30
|
#rpcBalanceAssetNames = []
|
|
31
|
-
constructor({
|
|
31
|
+
constructor({
|
|
32
|
+
server,
|
|
33
|
+
wsGatewayClient,
|
|
34
|
+
rpcBalanceAssetNames,
|
|
35
|
+
eip7702Supported,
|
|
36
|
+
config,
|
|
37
|
+
...args
|
|
38
|
+
} = {}) {
|
|
32
39
|
super(args)
|
|
33
40
|
assert(wsGatewayClient instanceof WsGateway, 'expected WsGateway wsGatewayClient')
|
|
34
41
|
|
|
@@ -36,6 +43,7 @@ export class ClarityMonitorV2 extends BaseMonitor {
|
|
|
36
43
|
this.server = server
|
|
37
44
|
this.#wsClient = wsGatewayClient
|
|
38
45
|
this.#rpcBalanceAssetNames = rpcBalanceAssetNames
|
|
46
|
+
this.eip7702Supported = eip7702Supported
|
|
39
47
|
this.getAllLogItemsByAsset = getAllLogItemsByAsset
|
|
40
48
|
this.deriveDataNeededForTick = getDeriveDataNeededForTick(this.aci)
|
|
41
49
|
this.deriveTransactionsToCheck = getDeriveTransactionsToCheck({
|
|
@@ -227,6 +235,7 @@ export class ClarityMonitorV2 extends BaseMonitor {
|
|
|
227
235
|
const eip7702Delegation = await getCurrentEIP7702Delegation({
|
|
228
236
|
server: this.server,
|
|
229
237
|
address: derivedData.ourWalletAddress,
|
|
238
|
+
eip7702Supported: this.eip7702Supported,
|
|
230
239
|
currentDelegation: derivedData.currentAccountState?.eip7702Delegation,
|
|
231
240
|
logger: this.logger,
|
|
232
241
|
})
|
|
@@ -23,11 +23,12 @@ import {
|
|
|
23
23
|
const { isEmpty } = lodash
|
|
24
24
|
|
|
25
25
|
export class ClarityMonitor extends BaseMonitor {
|
|
26
|
-
constructor({ server, config, rpcBalanceAssetNames, ...args }) {
|
|
26
|
+
constructor({ server, config, rpcBalanceAssetNames, eip7702Supported, ...args }) {
|
|
27
27
|
super(args)
|
|
28
28
|
this.config = { GAS_PRICE_FROM_WEBSOCKET: true, ...config }
|
|
29
29
|
this.server = server
|
|
30
30
|
this.rpcBalanceAssetNames = rpcBalanceAssetNames
|
|
31
|
+
this.eip7702Supported = eip7702Supported
|
|
31
32
|
this.getAllLogItemsByAsset = getAllLogItemsByAsset
|
|
32
33
|
this.deriveDataNeededForTick = getDeriveDataNeededForTick(this.aci)
|
|
33
34
|
this.deriveTransactionsToCheck = getDeriveTransactionsToCheck({
|
|
@@ -191,6 +192,7 @@ export class ClarityMonitor extends BaseMonitor {
|
|
|
191
192
|
const eip7702Delegation = await getCurrentEIP7702Delegation({
|
|
192
193
|
server: this.server,
|
|
193
194
|
address: derivedData.ourWalletAddress,
|
|
195
|
+
eip7702Supported: this.eip7702Supported,
|
|
194
196
|
currentDelegation: derivedData.currentAccountState?.eip7702Delegation,
|
|
195
197
|
logger: this.logger,
|
|
196
198
|
})
|
|
@@ -17,10 +17,11 @@ const { isEmpty, unionBy, zipObject } = lodash
|
|
|
17
17
|
// The base ethereum monitor no history class handles listening for assets with no history
|
|
18
18
|
|
|
19
19
|
export class EthereumNoHistoryMonitor extends BaseMonitor {
|
|
20
|
-
constructor({ server, config, ...args }) {
|
|
20
|
+
constructor({ server, config, eip7702Supported, ...args }) {
|
|
21
21
|
super(args)
|
|
22
22
|
this.server = server
|
|
23
23
|
this.config = { ...config }
|
|
24
|
+
this.eip7702Supported = eip7702Supported
|
|
24
25
|
this.deriveDataNeededForTick = getDeriveDataNeededForTick(this.aci)
|
|
25
26
|
this.deriveTransactionsToCheck = getDeriveTransactionsToCheck({
|
|
26
27
|
getTxLog: (...args) => this.aci.getTxLog(...args),
|
|
@@ -190,6 +191,7 @@ export class EthereumNoHistoryMonitor extends BaseMonitor {
|
|
|
190
191
|
const eip7702Delegation = await getCurrentEIP7702Delegation({
|
|
191
192
|
server: this.server,
|
|
192
193
|
address: ourWalletAddress,
|
|
194
|
+
eip7702Supported: this.eip7702Supported,
|
|
193
195
|
currentDelegation: currentAccountState?.eip7702Delegation,
|
|
194
196
|
logger: this.logger,
|
|
195
197
|
})
|