@exodus/ethereum-api 8.76.5 → 8.76.7

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/package.json +3 -4
  3. package/src/address-has-history.js +6 -2
  4. package/src/create-asset-plugin-factory.js +1 -0
  5. package/src/create-asset-utils.js +39 -35
  6. package/src/create-asset.js +26 -16
  7. package/src/eth-like-util.js +53 -0
  8. package/src/exodus-eth-server/api-coin-nodes.js +11 -84
  9. package/src/exodus-eth-server/clarity-v2.js +30 -51
  10. package/src/exodus-eth-server/clarity.js +2 -115
  11. package/src/exodus-eth-server/errors.js +5 -1
  12. package/src/exodus-eth-server/eth-like-server-base.js +123 -0
  13. package/src/exodus-eth-server/fetch-json.js +48 -0
  14. package/src/gas-estimation.js +19 -4
  15. package/src/get-balances.js +14 -0
  16. package/src/index.js +1 -0
  17. package/src/multicall3/index.js +169 -0
  18. package/src/simulation/common.js +34 -0
  19. package/src/simulation/create-simulate-message.js +49 -0
  20. package/src/simulation/create-simulate-transactions.js +106 -0
  21. package/src/simulation/estimate-fee.js +14 -0
  22. package/src/simulation/estimate-simple-transfer.js +15 -0
  23. package/src/simulation/get-message-type.js +18 -0
  24. package/src/simulation/simulate-message-api.js +68 -0
  25. package/src/simulation/simulate-transactions-api.js +265 -0
  26. package/src/simulation/simulate-transactions.js +16 -0
  27. package/src/simulation/transactions.js +52 -0
  28. package/src/simulation/try-estimating-changes-locally.js +26 -0
  29. package/src/staking/ethereum/staking-utils.js +3 -1
  30. package/src/staking/matic/matic-staking-utils.js +3 -1
  31. package/src/tx-log/clarity-truncated-history-monitor.js +34 -0
  32. package/src/tx-log/ethereum-no-history-monitor.js +2 -23
  33. package/src/tx-log/monitor-utils/get-batched-rpc-balances.js +28 -0
  34. package/src/tx-send/broadcast-error-handler.js +7 -2
  35. package/src/tx-send/tx-send.js +1 -0
  36. package/src/web3/createSimulateMessage.js +2 -1
  37. package/src/web3/createSimulateTransactions.js +3 -9
@@ -1,17 +1,15 @@
1
- import { bufferToHex } from '@exodus/ethereumjs/util'
2
1
  import { safeString } from '@exodus/safe-string'
3
- import SolidityContract from '@exodus/solidity-contract'
4
2
  import { TraceId } from '@exodus/traceparent'
5
- import EventEmitter from 'events/events.js'
6
3
  import io from 'socket.io-client'
7
4
 
8
5
  import { fromHexToString } from '../number-utils.js'
9
6
  import { errorMessageToSafeHint } from './errors.js'
7
+ import EthLikeServerBase from './eth-like-server-base.js'
10
8
  import { getFallbackGasPriceEstimation } from './utils.js'
11
9
 
12
10
  export const RPC_REQUEST_TIMEOUT = 'RPC_REQUEST_TIMEOUT'
13
11
 
14
- export default class ClarityServer extends EventEmitter {
12
+ export default class ClarityServer extends EthLikeServerBase {
15
13
  constructor({ baseAssetName, uri }) {
16
14
  super()
17
15
  this.baseAssetName = baseAssetName
@@ -20,7 +18,6 @@ export default class ClarityServer extends EventEmitter {
20
18
  this.defaultUri = uri
21
19
  this.baseNamespace = `/v1/${this.baseAssetName}`
22
20
  this.sockets = Object.create(null)
23
- this.id = 0
24
21
  }
25
22
 
26
23
  setURI(uri) {
@@ -246,116 +243,6 @@ export default class ClarityServer extends EventEmitter {
246
243
  return code.length > 2
247
244
  }
248
245
 
249
- buildRequest({ method, params = [] }) {
250
- return { jsonrpc: '2.0', id: this.id++, method, params }
251
- }
252
-
253
- balanceOfRequest(address, tokenAddress, tag = 'latest') {
254
- const contract = SolidityContract.simpleErc20(tokenAddress)
255
- const callData = contract.balanceOf.build(address)
256
- const data = {
257
- data: bufferToHex(callData),
258
- to: tokenAddress,
259
- }
260
- return this.ethCallRequest(data, tag)
261
- }
262
-
263
- getBalanceRequest(address, tag = 'latest') {
264
- return this.buildRequest({ method: 'eth_getBalance', params: [address, tag] })
265
- }
266
-
267
- gasPriceRequest() {
268
- return this.buildRequest({ method: 'eth_gasPrice' })
269
- }
270
-
271
- estimateGasRequest(data, tag = 'latest') {
272
- return this.buildRequest({ method: 'eth_estimateGas', params: [data, tag] })
273
- }
274
-
275
- sendRawTransactionRequest(data) {
276
- const _data = data instanceof Uint8Array ? Buffer.from(data).toString('hex') : data
277
- const hex = _data.startsWith('0x') ? _data : '0x' + _data
278
- return this.buildRequest({ method: 'eth_sendRawTransaction', params: [hex] })
279
- }
280
-
281
- coinbaseRequest() {
282
- return this.buildRequest({ method: 'eth_coinbase' })
283
- }
284
-
285
- getCodeRequest(address, tag = 'latest') {
286
- return this.buildRequest({ method: 'eth_getCode', params: [address, tag] })
287
- }
288
-
289
- getStorageAtRequest(address, position, tag = 'latest') {
290
- return this.buildRequest({ method: 'eth_getStorageAt', params: [address, position, tag] })
291
- }
292
-
293
- getTransactionCountRequest(address, tag = 'latest') {
294
- return this.buildRequest({ method: 'eth_getTransactionCount', params: [address, tag] })
295
- }
296
-
297
- getTransactionByHashRequest(hash) {
298
- return this.buildRequest({ method: 'eth_getTransactionByHash', params: [hash] })
299
- }
300
-
301
- getTransactionReceiptRequest(txhash) {
302
- return this.buildRequest({ method: 'eth_getTransactionReceipt', params: [txhash] })
303
- }
304
-
305
- ethCallRequest(data, tag = 'latest') {
306
- return this.buildRequest({ method: 'eth_call', params: [data, tag] })
307
- }
308
-
309
- blockNumberRequest() {
310
- return this.buildRequest({ method: 'eth_blockNumber' })
311
- }
312
-
313
- getLogsRequest(object) {
314
- return this.buildRequest({ method: 'eth_getLogs', params: [object] })
315
- }
316
-
317
- getBlockByNumberRequest(numberHex, isFullTxs = false) {
318
- return this.buildRequest({ method: 'eth_getBlockByNumber', params: [numberHex, isFullTxs] })
319
- }
320
-
321
- getBlockByHashRequest(blockHash, isFullTxs = false) {
322
- return this.buildRequest({ method: 'eth_getBlockByHash', params: [blockHash, isFullTxs] })
323
- }
324
-
325
- getBlockTransactionCountByHashRequest(blockHash) {
326
- return this.buildRequest({ method: 'eth_getBlockTransactionCountByHash', params: [blockHash] })
327
- }
328
-
329
- getBlockTransactionCountByNumberRequest(quantityOrTag) {
330
- return this.buildRequest({
331
- method: 'eth_getBlockTransactionCountByNumber',
332
- params: [quantityOrTag],
333
- })
334
- }
335
-
336
- getCompilersRequest() {
337
- return this.buildRequest({ method: 'eth_getCompilers' })
338
- }
339
-
340
- simulateV1Request(...params) {
341
- return this.buildRequest({
342
- method: 'eth_simulateV1',
343
- params,
344
- })
345
- }
346
-
347
- getNetVersionRequest() {
348
- return this.buildRequest({ method: 'net_version' })
349
- }
350
-
351
- simulateRawTransactionRequest(rawTx, applyPending = true) {
352
- const replaced = rawTx.replace('0x', '')
353
- return this.buildRequest({
354
- method: 'debug_simulateRawTransaction',
355
- params: [replaced, applyPending],
356
- })
357
- }
358
-
359
246
  // Transport: Via sendRequest → WS first → HTTP fallback in ClarityServerV2
360
247
  async proxyToCoinNode(params) {
361
248
  const request = this.buildRequest(params)
@@ -22,7 +22,11 @@ const DYNAMIC_RPC_ERRORS = {
22
22
  TRANSACTION_GAS_PRICE_BELOW_MINIMUM: safeString`transaction gas price below minimum`,
23
23
  }
24
24
 
25
- export const KNOWN_RPC_ERRORS = { ...TxPoolErrors, ...DYNAMIC_RPC_ERRORS }
25
+ const SERVO_ERRORS = {
26
+ EMPTY_BUNDLE: safeString`numTxs=0: invalid num txs`,
27
+ }
28
+
29
+ export const KNOWN_RPC_ERRORS = { ...TxPoolErrors, ...DYNAMIC_RPC_ERRORS, ...SERVO_ERRORS }
26
30
 
27
31
  export const tryMappingToRpcErrors = (errorMessage) => {
28
32
  if (typeof errorMessage !== 'string') return
@@ -0,0 +1,123 @@
1
+ import { bufferToHex } from '@exodus/ethereumjs/util'
2
+ import SolidityContract from '@exodus/solidity-contract'
3
+ import EventEmitter from 'events/events.js'
4
+ import assert from 'minimalistic-assert'
5
+
6
+ export default class EthLikeServerBase extends EventEmitter {
7
+ id = 0
8
+
9
+ buildRequest({ method, params = [] }) {
10
+ return { jsonrpc: '2.0', id: this.id++, method, params }
11
+ }
12
+
13
+ balanceOfRequest(address, tokenAddress, tag = 'latest') {
14
+ const contract = SolidityContract.simpleErc20(tokenAddress)
15
+ const callData = contract.balanceOf.build(address)
16
+ const data = {
17
+ data: bufferToHex(callData),
18
+ to: tokenAddress,
19
+ }
20
+ return this.ethCallRequest(data, tag)
21
+ }
22
+
23
+ getBalanceRequest(address, tag = 'latest') {
24
+ return this.buildRequest({ method: 'eth_getBalance', params: [address, tag] })
25
+ }
26
+
27
+ gasPriceRequest() {
28
+ return this.buildRequest({ method: 'eth_gasPrice' })
29
+ }
30
+
31
+ estimateGasRequest(data, tag = 'latest') {
32
+ return this.buildRequest({ method: 'eth_estimateGas', params: [data, tag] })
33
+ }
34
+
35
+ sendRawTransactionRequest(data) {
36
+ const _data = data instanceof Uint8Array ? Buffer.from(data).toString('hex') : data
37
+ const hex = _data.startsWith('0x') ? _data : '0x' + _data
38
+ return this.buildRequest({ method: 'eth_sendRawTransaction', params: [hex] })
39
+ }
40
+
41
+ coinbaseRequest() {
42
+ return this.buildRequest({ method: 'eth_coinbase' })
43
+ }
44
+
45
+ getCodeRequest(address, tag = 'latest') {
46
+ return this.buildRequest({ method: 'eth_getCode', params: [address, tag] })
47
+ }
48
+
49
+ getStorageAtRequest(address, position, tag = 'latest') {
50
+ return this.buildRequest({ method: 'eth_getStorageAt', params: [address, position, tag] })
51
+ }
52
+
53
+ getTransactionCountRequest(address, tag = 'latest') {
54
+ return this.buildRequest({ method: 'eth_getTransactionCount', params: [address, tag] })
55
+ }
56
+
57
+ getTransactionByHashRequest(hash) {
58
+ return this.buildRequest({ method: 'eth_getTransactionByHash', params: [hash] })
59
+ }
60
+
61
+ getTransactionReceiptRequest(txhash) {
62
+ return this.buildRequest({ method: 'eth_getTransactionReceipt', params: [txhash] })
63
+ }
64
+
65
+ ethCallRequest(data, tag = 'latest') {
66
+ return this.buildRequest({ method: 'eth_call', params: [data, tag] })
67
+ }
68
+
69
+ blockNumberRequest() {
70
+ return this.buildRequest({ method: 'eth_blockNumber' })
71
+ }
72
+
73
+ getLogsRequest(object) {
74
+ return this.buildRequest({ method: 'eth_getLogs', params: [object] })
75
+ }
76
+
77
+ getBlockByNumberRequest(numberHex, isFullTxs = false) {
78
+ return this.buildRequest({ method: 'eth_getBlockByNumber', params: [numberHex, isFullTxs] })
79
+ }
80
+
81
+ getBlockByHashRequest(blockHash, isFullTxs = false) {
82
+ return this.buildRequest({ method: 'eth_getBlockByHash', params: [blockHash, isFullTxs] })
83
+ }
84
+
85
+ getBlockTransactionCountByHashRequest(blockHash) {
86
+ return this.buildRequest({ method: 'eth_getBlockTransactionCountByHash', params: [blockHash] })
87
+ }
88
+
89
+ getBlockTransactionCountByNumberRequest(quantityOrTag) {
90
+ return this.buildRequest({
91
+ method: 'eth_getBlockTransactionCountByNumber',
92
+ params: [quantityOrTag],
93
+ })
94
+ }
95
+
96
+ getCompilersRequest() {
97
+ return this.buildRequest({ method: 'eth_getCompilers' })
98
+ }
99
+
100
+ simulateV1Request(...params) {
101
+ return this.buildRequest({
102
+ method: 'eth_simulateV1',
103
+ params,
104
+ })
105
+ }
106
+
107
+ getNetVersionRequest() {
108
+ return this.buildRequest({ method: 'net_version' })
109
+ }
110
+
111
+ simulateRawTransactionRequest(rawTx, applyPending = true) {
112
+ const replaced = rawTx.replace('0x', '')
113
+ return this.buildRequest({
114
+ method: 'debug_simulateRawTransaction',
115
+ params: [replaced, applyPending],
116
+ })
117
+ }
118
+
119
+ sendBundleRequest({ txs }) {
120
+ assert(Array.isArray(txs), 'expected array txs')
121
+ return this.buildRequest({ method: 'eth_sendBundle', params: [{ txs }] })
122
+ }
123
+ }
@@ -0,0 +1,48 @@
1
+ import { retry } from '@exodus/simple-retry'
2
+ import { TraceId } from '@exodus/traceparent'
3
+
4
+ const getTextFromResponse = async (response) => {
5
+ try {
6
+ const responseBody = await response.text()
7
+ return responseBody.slice(0, 100)
8
+ } catch {
9
+ return ''
10
+ }
11
+ }
12
+
13
+ export const fetchJson = async (url, fetchOptions) => {
14
+ const response = await fetch(url, fetchOptions)
15
+
16
+ if (!response.ok) {
17
+ const traceId = TraceId.fromResponse(response)
18
+ const error = new Error(
19
+ `${url} returned ${response.status}: ${
20
+ response.statusText || 'Unknown Status Text'
21
+ }. Body: ${await getTextFromResponse(response)}`
22
+ )
23
+ if (traceId) {
24
+ error.traceId = traceId
25
+ }
26
+
27
+ throw error
28
+ }
29
+
30
+ const json = await response.json()
31
+
32
+ // Only capture trace ID if there's an RPC error in the response
33
+ // (consumers extract it via __traceId when throwing the error)
34
+ if (json.error) {
35
+ const traceId = TraceId.fromResponse(response)
36
+ if (traceId) {
37
+ json.__traceId = traceId
38
+ }
39
+ }
40
+
41
+ return json
42
+ }
43
+
44
+ export const fetchJsonRetry = (url, fetchOptions) => {
45
+ const waitTimes = ['3s']
46
+ const fetchWithRetry = retry(fetchJson, { delayTimesMs: waitTimes })
47
+ return fetchWithRetry(url, fetchOptions)
48
+ }
@@ -98,12 +98,27 @@ export async function resolveGasLimitMultiplier({ asset, feeData, toAddress, fro
98
98
  return DEFAULT_GAS_LIMIT_MULTIPLIER
99
99
  }
100
100
 
101
+ // https://eips.ethereum.org/EIPS/eip-7623
102
+ export const getEip7623CalldataCost = (calldata) => {
103
+ calldata = toBuffer(calldata)
104
+
105
+ const TOTAL_COST_FLOOR_PER_TOKEN = 10
106
+
107
+ const nonZeroBytesInCalldata = calldata.filter(Boolean).length
108
+ const zeroBytesInCalldata = calldata.length - nonZeroBytesInCalldata
109
+ const tokensInCalldata = zeroBytesInCalldata + nonZeroBytesInCalldata * 4
110
+
111
+ return TOTAL_COST_FLOOR_PER_TOKEN * tokensInCalldata
112
+ }
113
+
101
114
  export const defaultGasLimit = ({ asset, txInput }) => {
102
115
  const isToken = isEthereumLikeToken(asset)
103
- return (
104
- (isToken ? DEFAULT_TOKEN_GAS_LIMIT : DEFAULT_GAS_LIMIT) +
105
- GAS_PER_NON_ZERO_BYTE * toBuffer(txInput).length
106
- )
116
+
117
+ const calldataCost = asset.baseAsset.eip7623Supported
118
+ ? getEip7623CalldataCost(txInput)
119
+ : GAS_PER_NON_ZERO_BYTE * toBuffer(txInput).length
120
+
121
+ return (isToken ? DEFAULT_TOKEN_GAS_LIMIT : DEFAULT_GAS_LIMIT) + calldataCost
107
122
  }
108
123
 
109
124
  // TODO: `gasLimit` needs to be a responsibility of `resolveTxAttributesByTxType`.
@@ -293,6 +293,20 @@ export const getBalancesFactory = ({ monitorType, useAbsoluteBalance, rpcBalance
293
293
  }
294
294
  }
295
295
 
296
+ // A pending send already reflected in the account-state reading is double-counted
297
+ // via `unconfirmedSent`, making spendable transiently negative (bounded by
298
+ // `unconfirmedSent`). A negative beyond that bound is a real accounting bug.
299
+ if (spendable.isNegative && spendable.abs().gt(unconfirmedSent)) {
300
+ console.warn('unexpected negative spendable beyond pending sends', {
301
+ assetName: asset.name,
302
+ spendable: spendable.toBaseString(),
303
+ unconfirmedSent: unconfirmedSent.toBaseString(),
304
+ })
305
+ }
306
+
307
+ // Clamp before deriving `total` so the artifact doesn't drag it below staked balances.
308
+ spendable = spendable.clampLowerZero()
309
+
296
310
  const total = spendable.add(staked).add(staking).add(unstaking).add(unstaked)
297
311
  const stakeable = spendable
298
312
 
package/src/index.js CHANGED
@@ -61,6 +61,7 @@ export {
61
61
  } from './staking/index.js'
62
62
 
63
63
  export { fetchTxPreview, maybeRemoveDuplicates, retrieveSideEffects } from './simulate-tx/index.js'
64
+ export { simulateTransactions } from './simulation/simulate-transactions.js'
64
65
 
65
66
  export {
66
67
  isZeroAllowanceAsset,
@@ -0,0 +1,169 @@
1
+ import { memoize } from '@exodus/basic-utils'
2
+ import { ABI } from '@exodus/ethereum-lib'
3
+ import { bufferToHex } from '@exodus/ethereumjs/util'
4
+ import SolidityContract from '@exodus/solidity-contract'
5
+ import assert from 'minimalistic-assert'
6
+
7
+ import EthLikeServerBase from '../exodus-eth-server/eth-like-server-base.js'
8
+ import { BLOCK_TAG_LATEST } from '../tx-send/nonce-utils.js'
9
+
10
+ const assertValidMulticall3BlockTag = (blockTag) =>
11
+ assert(blockTag === BLOCK_TAG_LATEST, 'blockTag must be "latest" for multicall3')
12
+
13
+ const SUPPORTED_METHODS = new Set(['eth_getBalance', 'eth_blockNumber', 'eth_call'])
14
+
15
+ const assertSupportedMethod = (method) => {
16
+ assert(
17
+ SUPPORTED_METHODS.has(method),
18
+ `method "${method}" is not supported for static call batching`
19
+ )
20
+ }
21
+
22
+ const getMulticall3Contract = memoize(() => new SolidityContract(ABI.multicall3))
23
+
24
+ export class EthLikeRpcRequestAccumulator extends EthLikeServerBase {
25
+ #requestContext = null
26
+ #requests = []
27
+
28
+ #withRequestContext(requestContext, ...args) {
29
+ assert(this.#requestContext === null)
30
+ this.#requestContext = requestContext
31
+
32
+ const result = super[requestContext](...args)
33
+
34
+ this.#requestContext = null
35
+ return result
36
+ }
37
+
38
+ _serializeRequest({ context: _, originalRequest }) {
39
+ return super.buildRequest(originalRequest)
40
+ }
41
+
42
+ async _execute({ requests, server }) {
43
+ return server.sendBatchRequest(requests.map(({ request }) => request))
44
+ }
45
+
46
+ buildRequest(originalRequest) {
47
+ const { method, params } = originalRequest
48
+ assertSupportedMethod(method)
49
+
50
+ if (method === 'eth_getBalance' || method === 'eth_call') {
51
+ const tag = params[1]
52
+ assertValidMulticall3BlockTag(tag)
53
+ }
54
+
55
+ const context = this.#requestContext ?? method
56
+
57
+ void this.#requests.push({
58
+ context,
59
+ originalRequest,
60
+ request: this._serializeRequest({ context, originalRequest }),
61
+ })
62
+
63
+ return this
64
+ }
65
+
66
+ balanceOfRequest(...args) {
67
+ return this.#withRequestContext('balanceOfRequest', ...args)
68
+ }
69
+
70
+ length() {
71
+ return this.#requests.length
72
+ }
73
+
74
+ reset() {
75
+ this.#requests.length = 0
76
+ }
77
+
78
+ async flush(server) {
79
+ assert(server, 'expected server')
80
+
81
+ const requests = [...this.#requests]
82
+ this.reset()
83
+
84
+ if (requests.length === 0) return []
85
+
86
+ const results = await this._execute({ requests, server })
87
+
88
+ return results.map((result, i) => {
89
+ const request = requests[i]
90
+ assert(request)
91
+
92
+ const { context, originalRequest } = request
93
+
94
+ if (context === 'eth_getBalance') return `0x${BigInt(result).toString(16)}`
95
+ if (context === 'eth_blockNumber') return `0x${BigInt(result).toString(16)}`
96
+ if (context === 'balanceOfRequest') {
97
+ const {
98
+ params: [{ to: tokenAddress }],
99
+ } = originalRequest
100
+ return {
101
+ confirmed: {
102
+ [tokenAddress]: BigInt(result).toString(),
103
+ },
104
+ }
105
+ }
106
+
107
+ return result
108
+ })
109
+ }
110
+ }
111
+
112
+ export class EthLikeMulticall3RpcRequestAccumulator extends EthLikeRpcRequestAccumulator {
113
+ #multicall3Address
114
+ #multicall3Contract
115
+
116
+ constructor({ multicall3Address }) {
117
+ super()
118
+
119
+ assert(typeof multicall3Address === 'string')
120
+ this.#multicall3Address = multicall3Address
121
+ this.#multicall3Contract = getMulticall3Contract()
122
+ }
123
+
124
+ _serializeRequest({ context: _, originalRequest: { method, params } }) {
125
+ switch (method) {
126
+ case 'eth_getBalance':
127
+ return {
128
+ address: this.#multicall3Address,
129
+ calldata: bufferToHex(this.#multicall3Contract.getEthBalance.build(params[0])),
130
+ }
131
+ case 'eth_blockNumber':
132
+ return {
133
+ address: this.#multicall3Address,
134
+ calldata: bufferToHex(this.#multicall3Contract.getBlockNumber.build()),
135
+ }
136
+ case 'eth_call': {
137
+ const [data] = params
138
+ const { to, data: calldata } = data
139
+ return { address: to, calldata }
140
+ }
141
+
142
+ default:
143
+ assert(false)
144
+ }
145
+ }
146
+
147
+ async _execute({ requests, server }) {
148
+ const data = await server.ethCall({
149
+ data: bufferToHex(
150
+ this.#multicall3Contract.aggregate.build(
151
+ requests.map(({ request: { address, calldata } }) => [address, calldata])
152
+ )
153
+ ),
154
+ to: this.#multicall3Address,
155
+ })
156
+
157
+ const multicall3Result = this.#multicall3Contract.decodeOutput({ data, method: 'aggregate' })
158
+
159
+ assert(
160
+ Array.isArray(multicall3Result) && multicall3Result.length === 2,
161
+ 'invalid multicall3Result'
162
+ )
163
+
164
+ const results = multicall3Result[1].map((buf) => bufferToHex(buf))
165
+ assert(results.length === requests.length)
166
+
167
+ return results
168
+ }
169
+ }
@@ -0,0 +1,34 @@
1
+ import BN from 'bn.js'
2
+
3
+ export const BLOWFISH_EVM_CHAINS = {
4
+ avalanchec: {
5
+ network: 'avalanche',
6
+ chain: 'mainnet',
7
+ },
8
+ basemainnet: {
9
+ network: 'base',
10
+ chain: 'mainnet',
11
+ },
12
+ bsc: {
13
+ network: 'bnb',
14
+ chain: 'mainnet',
15
+ },
16
+ ethereum: {
17
+ network: 'ethereum',
18
+ chain: 'mainnet',
19
+ },
20
+ ethereumarbone: {
21
+ network: 'arbitrum',
22
+ chain: 'one',
23
+ },
24
+ matic: {
25
+ network: 'polygon',
26
+ chain: 'mainnet',
27
+ },
28
+ optimism: {
29
+ network: 'optimism',
30
+ chain: 'mainnet',
31
+ },
32
+ }
33
+
34
+ export const MAX_INT256_SOLIDITY = new BN(2).pow(new BN(255)).subn(1)
@@ -0,0 +1,49 @@
1
+ import { tryParsingSIWE } from '@exodus/web3-utils'
2
+ import assert from 'minimalistic-assert'
3
+
4
+ import { getMessageType, MessageTypeEnum } from './get-message-type.js'
5
+ import { simulateMessageApi } from './simulate-message-api.js'
6
+
7
+ export const createSimulateMessage =
8
+ ({
9
+ apiEndpoint = 'https://simulation.a.exodus.io/simulateMessage',
10
+ headers = {
11
+ 'X-Api-Version': '2023-06-05',
12
+ },
13
+ } = {}) =>
14
+ async ({ message, url, asset, address }) => {
15
+ assert(url instanceof URL, "'url' should be an instance of the URL object.")
16
+
17
+ const simulationResult = {
18
+ baseAssetName: asset.baseAssetName,
19
+ action: 'NONE',
20
+ }
21
+
22
+ const messageType = getMessageType(message)
23
+ if (messageType === MessageTypeEnum.Unknown) {
24
+ return simulationResult
25
+ }
26
+
27
+ if (messageType === MessageTypeEnum.RawMessage) {
28
+ tryParsingSIWE({
29
+ address,
30
+ message,
31
+ url,
32
+ simulationResult,
33
+ })
34
+ }
35
+
36
+ await simulateMessageApi({
37
+ address,
38
+ message: {
39
+ message,
40
+ messageType,
41
+ },
42
+ url,
43
+ apiEndpoint,
44
+ headers,
45
+ simulationResult,
46
+ })
47
+
48
+ return simulationResult
49
+ }