@exodus/ethereum-api 8.13.3 → 8.15.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 CHANGED
@@ -3,6 +3,25 @@
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.15.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.14.0...@exodus/ethereum-api@8.15.0) (2024-08-27)
7
+
8
+
9
+ ### Features
10
+
11
+ * introduce Clarity V2 server ([#2982](https://github.com/ExodusMovement/assets/issues/2982)) ([90ebbf0](https://github.com/ExodusMovement/assets/commit/90ebbf0b48c118c1aa50f1b8adb4c941c3344f1b))
12
+
13
+
14
+
15
+ ## [8.14.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.13.3...@exodus/ethereum-api@8.14.0) (2024-08-26)
16
+
17
+
18
+ ### Features
19
+
20
+ * allow custom gasPriceEconomicalRate ([#3236](https://github.com/ExodusMovement/assets/issues/3236)) ([acdf78e](https://github.com/ExodusMovement/assets/commit/acdf78e20c9f93da2cafa0045f24e5ad4f2e0a5d))
21
+ * forceGasLimitEstimation asset plugin param ([#3237](https://github.com/ExodusMovement/assets/issues/3237)) ([7da77dd](https://github.com/ExodusMovement/assets/commit/7da77dd8f09bddc752dc113b5ef875bf1ff5263c))
22
+
23
+
24
+
6
25
  ## [8.13.3](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-api@8.13.2...@exodus/ethereum-api@8.13.3) (2024-08-13)
7
26
 
8
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/ethereum-api",
3
- "version": "8.13.3",
3
+ "version": "8.15.0",
4
4
  "description": "Ethereum Api",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -22,7 +22,7 @@
22
22
  "dependencies": {
23
23
  "@exodus/asset": "^1.2.0",
24
24
  "@exodus/asset-lib": "^4.2.2",
25
- "@exodus/assets": "^9.1.1",
25
+ "@exodus/assets": "^11.0.0",
26
26
  "@exodus/basic-utils": "^2.1.0",
27
27
  "@exodus/bip44-constants": "^195.0.0",
28
28
  "@exodus/crypto": "^1.0.0-rc.0",
@@ -65,5 +65,5 @@
65
65
  "type": "git",
66
66
  "url": "git+https://github.com/ExodusMovement/assets.git"
67
67
  },
68
- "gitHead": "71031eb3482dd28419a5b53df1ba83c45011095f"
68
+ "gitHead": "0ab4b1325214507e17398f71cfeb7e37c19c6c15"
69
69
  }
@@ -158,6 +158,7 @@ export const fromAddEthereumChainParameterToFactoryParams = (params) => {
158
158
  confirmationsNumber: 5,
159
159
  monitorType: 'no-history',
160
160
  isTestnet: params.isTestnet,
161
+ ...params.plugin, // extra plugin configuration
161
162
  },
162
163
  baseFeePerGas: params.baseFeePerGas,
163
164
  gasPrice: params.gasPrice,
@@ -1,6 +1,6 @@
1
1
  import { connectAssetsList } from '@exodus/assets'
2
2
  import { pick } from '@exodus/basic-utils'
3
- import bip44Constants from '@exodus/bip44-constants/by-ticker'
3
+ import bip44Constants from '@exodus/bip44-constants/by-ticker.js'
4
4
  import {
5
5
  createEthereumLikeAccountState,
6
6
  createGetKeyIdentifier as defaultCreateGetKeyIdentifier,
@@ -57,6 +57,7 @@ export const createAssetFactory = ({
57
57
  serverUrl,
58
58
  stakingConfiguration = {},
59
59
  useEip1191ChainIdChecksum = false,
60
+ forceGasLimitEstimation = false,
60
61
  }) => {
61
62
  assert(assetsList, 'assetsList is required')
62
63
  assert(feeData, 'feeData is required')
@@ -160,6 +161,7 @@ export const createAssetFactory = ({
160
161
  let monitor
161
162
  switch (monitorType) {
162
163
  case 'clarity':
164
+ case 'clarity-v2':
163
165
  monitor = new ClarityMonitor({
164
166
  assetClientInterface,
165
167
  interval: ms(monitorInterval || '5m'),
@@ -269,6 +271,7 @@ export const createAssetFactory = ({
269
271
  chainId,
270
272
  monitorType,
271
273
  estimateL1DataFee,
274
+ forceGasLimitEstimation,
272
275
  server,
273
276
  ...(erc20FuelBuffer && { erc20FuelBuffer }),
274
277
  ...(fuelThreshold && { fuelThreshold: asset.currency.defaultUnit(fuelThreshold) }),
@@ -0,0 +1,90 @@
1
+ import { fetch } from '@exodus/fetch'
2
+ import { retry } from '@exodus/simple-retry'
3
+
4
+ import ClarityServer from './clarity'
5
+
6
+ const getTextFromResponse = async (response) => {
7
+ try {
8
+ const responseBody = await response.text()
9
+ return responseBody.slice(0, 100)
10
+ } catch {
11
+ return ''
12
+ }
13
+ }
14
+
15
+ const fetchJson = async (url, fetchOptions) => {
16
+ const response = await fetch(url, fetchOptions)
17
+
18
+ if (!response.ok)
19
+ throw new Error(
20
+ `${url} returned ${response.status}: ${
21
+ response.statusText || 'Unknown Status Text'
22
+ }. Body: ${await getTextFromResponse(response)}`
23
+ )
24
+ return response.json()
25
+ }
26
+
27
+ async function fetchJsonRetry(url, fetchOptions) {
28
+ const waitTimes = ['3s']
29
+ const fetchWithRetry = retry(fetchJson, { delayTimesMs: waitTimes })
30
+ return fetchWithRetry(url, fetchOptions)
31
+ }
32
+
33
+ export default class ClarityServerV2 extends ClarityServer {
34
+ constructor({ baseAssetName, uri }) {
35
+ super({ baseAssetName, uri })
36
+ this.baseApiPath = this.uri + `/api/v2/${this.baseAssetName}`
37
+ }
38
+
39
+ async getAllTransactions({ address, cursor }) {
40
+ let { blockNumber } = this.#decodeCursor(cursor)
41
+ blockNumber = blockNumber.toString()
42
+
43
+ const transactions = []
44
+
45
+ while (true) {
46
+ const url = new URL(`${this.baseApiPath}/addresses/${address}/transactions`)
47
+ url.searchParams.set('cursor', blockNumber)
48
+ url.searchParams.set('withInput', 'true')
49
+
50
+ const { transactions: txs, cursor: nextBlockNumber } = await fetchJsonRetry(url)
51
+
52
+ if (txs.length === 0) {
53
+ // fetch until no more new transactions
54
+ blockNumber = nextBlockNumber
55
+ break
56
+ }
57
+
58
+ if (nextBlockNumber <= blockNumber) {
59
+ console.warn('Invalid cursor: next block number is not greater than current block number')
60
+ }
61
+
62
+ transactions.push(...txs)
63
+ blockNumber = nextBlockNumber
64
+ }
65
+
66
+ const newCursor = Buffer.alloc(8)
67
+ newCursor.writeBigUInt64LE(BigInt(blockNumber), 0)
68
+
69
+ return {
70
+ transactions: {
71
+ confirmed: transactions,
72
+ pending: [],
73
+ },
74
+ cursor: newCursor,
75
+ }
76
+ }
77
+
78
+ #decodeCursor(cursor) {
79
+ if (Buffer.isBuffer(cursor)) {
80
+ // New format: buffer containing only the block number
81
+ if (cursor.length === 8) return { blockNumber: cursor.readBigUInt64LE(0) }
82
+
83
+ // Old format: buffer with length 26
84
+ if (cursor.length === 26) return { blockNumber: cursor.readBigInt64LE(10) }
85
+ }
86
+
87
+ // Doesn't match any known format, return default
88
+ return { blockNumber: BigInt(0) }
89
+ }
90
+ }
@@ -1,9 +1,9 @@
1
1
  import {
2
- // eslint-disable-next-line import/no-deprecated
2
+ // eslint-disable-next-line @exodus/import/no-deprecated
3
3
  DEFAULT_SERVER_URLS,
4
- // eslint-disable-next-line import/no-deprecated
4
+ // eslint-disable-next-line @exodus/import/no-deprecated
5
5
  ETHEREUM_LIKE_ASSETS,
6
- // eslint-disable-next-line import/no-deprecated
6
+ // eslint-disable-next-line @exodus/import/no-deprecated
7
7
  ETHEREUM_LIKE_MONITOR_TYPES,
8
8
  } from '@exodus/ethereum-lib'
9
9
  import assert from 'minimalistic-assert'
@@ -11,6 +11,7 @@ import assert from 'minimalistic-assert'
11
11
  import { create } from './api'
12
12
  import ApiCoinNodesServer from './api-coin-nodes'
13
13
  import ClarityServer from './clarity'
14
+ import ClarityServerV2 from './clarity-v2'
14
15
 
15
16
  export function createEvmServer({ assetName, serverUrl, monitorType }) {
16
17
  assert(assetName, 'assetName is required')
@@ -21,6 +22,8 @@ export function createEvmServer({ assetName, serverUrl, monitorType }) {
21
22
  return new ApiCoinNodesServer({ uri: serverUrl })
22
23
  case 'clarity':
23
24
  return new ClarityServer({ baseAssetName: assetName, uri: serverUrl })
25
+ case 'clarity-v2':
26
+ return new ClarityServerV2({ baseAssetName: assetName, uri: serverUrl })
24
27
  case 'magnifier':
25
28
  return create(serverUrl, assetName)
26
29
  default:
@@ -30,11 +33,11 @@ export function createEvmServer({ assetName, serverUrl, monitorType }) {
30
33
 
31
34
  // @Deprecated
32
35
  const serverMap = Object.fromEntries(
33
- // eslint-disable-next-line import/no-deprecated
36
+ // eslint-disable-next-line @exodus/import/no-deprecated
34
37
  ETHEREUM_LIKE_ASSETS.map((assetName) => {
35
- // eslint-disable-next-line import/no-deprecated
38
+ // eslint-disable-next-line @exodus/import/no-deprecated
36
39
  const monitorType = ETHEREUM_LIKE_MONITOR_TYPES[assetName]
37
- // eslint-disable-next-line import/no-deprecated
40
+ // eslint-disable-next-line @exodus/import/no-deprecated
38
41
  const serverUrl = DEFAULT_SERVER_URLS[assetName]
39
42
  return [assetName, createEvmServer({ assetName, serverUrl, monitorType })]
40
43
  })
@@ -74,8 +74,9 @@ export async function fetchGasLimit({
74
74
  toAddress = asset.contract.address
75
75
  } else if (
76
76
  !isContract &&
77
- // hacky, convert this to a fetchGasLimit forceGasLimitEstimation plugin flag!
77
+ !asset.forceGasLimitEstimation &&
78
78
  ![
79
+ // back compatiblity until all plugins are updated. Then remove this array
79
80
  'ethereumarbone',
80
81
  'ethereumarbonesepolia',
81
82
  'ethereumarbnova',
package/src/get-fee.js CHANGED
@@ -7,16 +7,19 @@ const taxes = {
7
7
 
8
8
  const getGasPriceMultiplier = ({ asset, feeData, isExchange, isSendAll, isRbfAllowed }) => {
9
9
  // exchanges quotes expire, do not risk having a stuck tx
10
- if (isExchange) return 1
10
+
11
+ const gasPriceMultiplier = feeData.gasPriceMultiplier || 1
12
+
13
+ if (isExchange) return gasPriceMultiplier
11
14
 
12
15
  // if eip1559 enabled, do not risk not leaving enough ETH to cover base fee (applies only for native asset)
13
16
  // (gasPrice difference will be reimbursed anyway: users do not overpay)
14
- if (isSendAll && isEthereumLike(asset) && feeData.eip1559Enabled) return 1
17
+ if (isSendAll && isEthereumLike(asset) && feeData.eip1559Enabled) return gasPriceMultiplier
15
18
 
16
19
  // do not risk having a stuck tx if we're not able to accelerate it
17
- if (!isRbfAllowed || !feeData.rbfEnabled) return 1
20
+ if (!isRbfAllowed || !feeData.rbfEnabled) return gasPriceMultiplier
18
21
 
19
- return feeData.gasPriceEconomicalRate
22
+ return feeData.gasPriceEconomicalRate || gasPriceMultiplier
20
23
  }
21
24
 
22
25
  const getExtraFeeData = ({ asset, amount }) => {
@@ -96,7 +96,7 @@ export class MaticStakingApi {
96
96
  /**
97
97
  * UnbondNonce is a counter stored in the contract that tracks each time a delegator unstakes
98
98
  * @param address delegator address
99
- * @return current unbonded nonce
99
+ * @returns current unbonded nonce
100
100
  */
101
101
  getCurrentUnbondNonce = async (address) => {
102
102
  const unbondNonce = await this.callReadFunctionContract(
@@ -1,21 +1,2 @@
1
- /**
2
- * This is a "light" version of @exodus/core resolution to select the native WebSocket on BE
3
- * It's a workaround until https://github.com/ExodusMovement/assets/pull/72 is merged.
4
- *
5
- * Based on https://github.com/ExodusMovement/fetch/blob/master/core.js , note that chooses native on Desktop
6
- */
7
- if (typeof process !== 'undefined' && (process.type === 'renderer' || process.type === 'worker')) {
8
- // THIS IS FOR DESKTOP
9
- if (process.env.EXODUS_DISABLE_WS) {
10
- module.exports = globalThis.WebSocket
11
- } else {
12
- module.exports = require('ws')
13
- }
14
- // eslint-disable-next-line no-undef
15
- } else if (typeof WebSocket === 'undefined') {
16
- // THIS IS FOR UNIT TESTING.
17
- module.exports = require('ws')
18
- } else {
19
- // THIS IS FOR BE
20
- module.exports = globalThis.WebSocket
21
- }
1
+ // Uses cjs to optimize out requiring / bundling ws
2
+ export { default } from './websocket.cjs'
@@ -0,0 +1,21 @@
1
+ /**
2
+ * This is a "light" version of @exodus/core resolution to select the native WebSocket on BE
3
+ * It's a workaround until https://github.com/ExodusMovement/assets/pull/72 is merged.
4
+ *
5
+ * Based on https://github.com/ExodusMovement/fetch/blob/master/core.js , note that chooses native on Desktop
6
+ */
7
+ if (typeof process !== 'undefined' && (process.type === 'renderer' || process.type === 'worker')) {
8
+ // THIS IS FOR DESKTOP
9
+ if (process.env.EXODUS_DISABLE_WS) {
10
+ module.exports = globalThis.WebSocket
11
+ } else {
12
+ module.exports = require('ws')
13
+ }
14
+ // eslint-disable-next-line no-undef
15
+ } else if (typeof WebSocket === 'undefined') {
16
+ // THIS IS FOR UNIT TESTING.
17
+ module.exports = require('ws')
18
+ } else {
19
+ // THIS IS FOR BE
20
+ module.exports = globalThis.WebSocket
21
+ }