@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 +19 -0
- package/package.json +3 -3
- package/src/create-asset-plugin-factory.js +1 -0
- package/src/create-asset.js +4 -1
- package/src/exodus-eth-server/clarity-v2.js +90 -0
- package/src/exodus-eth-server/index.js +9 -6
- package/src/gas-estimation.js +2 -1
- package/src/get-fee.js +7 -4
- package/src/staking/matic/api.js +1 -1
- package/src/websocket/index.js +2 -21
- package/src/websocket/websocket.cjs +21 -0
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.
|
|
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": "^
|
|
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": "
|
|
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,
|
package/src/create-asset.js
CHANGED
|
@@ -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
|
})
|
package/src/gas-estimation.js
CHANGED
|
@@ -74,8 +74,9 @@ export async function fetchGasLimit({
|
|
|
74
74
|
toAddress = asset.contract.address
|
|
75
75
|
} else if (
|
|
76
76
|
!isContract &&
|
|
77
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 }) => {
|
package/src/staking/matic/api.js
CHANGED
|
@@ -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
|
-
* @
|
|
99
|
+
* @returns current unbonded nonce
|
|
100
100
|
*/
|
|
101
101
|
getCurrentUnbondNonce = async (address) => {
|
|
102
102
|
const unbondNonce = await this.callReadFunctionContract(
|
package/src/websocket/index.js
CHANGED
|
@@ -1,21 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
+
}
|