@exodus/ethereum-lib 5.12.0 → 5.13.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/constants.js +0 -14
- package/src/unsigned-tx/create-ethereumjs-tx.js +47 -5
- package/src/unsigned-tx/parse-unsigned-tx.js +91 -17
- package/src/utils/index.js +2 -8
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
|
+
## [5.13.1](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-lib@5.13.0...@exodus/ethereum-lib@5.13.1) (2025-06-23)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: basemainnet main asset rpc only (#5904)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [5.13.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-lib@5.12.0...@exodus/ethereum-lib@5.13.0) (2025-06-18)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
* feat: allow transactionBuffer in unsignedTx (#5883)
|
|
23
|
+
|
|
24
|
+
* feat: remove eth sepolia and goerli (#5885)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
## [5.12.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-lib@5.11.0...@exodus/ethereum-lib@5.12.0) (2025-06-11)
|
|
7
29
|
|
|
8
30
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/ethereum-lib",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.13.1",
|
|
4
4
|
"description": "Ethereum utils, such as for cryptography, address encoding/decoding, transaction building, etc.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@exodus/basic-utils": "^3.0.1",
|
|
25
25
|
"@exodus/crypto": "^1.0.0-rc.18",
|
|
26
26
|
"@exodus/currency": "^6.0.1",
|
|
27
|
-
"@exodus/ethereumjs": "^1.
|
|
27
|
+
"@exodus/ethereumjs": "^1.6.0",
|
|
28
28
|
"@exodus/key-utils": "^3.7.0",
|
|
29
29
|
"@exodus/models": "^12.13.0",
|
|
30
30
|
"@exodus/solidity-contract": "^1.1.3",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"type": "git",
|
|
51
51
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "ff29985705f3a5b14aba9fff28709fa2ef395a45"
|
|
54
54
|
}
|
package/src/constants.js
CHANGED
|
@@ -12,21 +12,11 @@ const CHAIN_DATA = {
|
|
|
12
12
|
serverUrl: 'https://getc.a.exodus.io/wallet/v1/',
|
|
13
13
|
confirmationsNumber: 5000,
|
|
14
14
|
},
|
|
15
|
-
ethereumgoerli: {
|
|
16
|
-
chainId: 5,
|
|
17
|
-
serverUrl: 'https://geth-goerli-testnet-d.a.exodus.io/wallet/v1/',
|
|
18
|
-
confirmationsNumber: 30,
|
|
19
|
-
},
|
|
20
15
|
ethereumholesky: {
|
|
21
16
|
chainId: 17_000,
|
|
22
17
|
serverUrl: 'https://geth-holesky-testnet-d.a.exodus.io/wallet/v1/',
|
|
23
18
|
confirmationsNumber: 30,
|
|
24
19
|
},
|
|
25
|
-
ethereumsepolia: {
|
|
26
|
-
chainId: 11_155_111,
|
|
27
|
-
serverUrl: 'https://geth-sepolia-testnet-d.a.exodus.io/wallet/v1/',
|
|
28
|
-
confirmationsNumber: 30,
|
|
29
|
-
},
|
|
30
20
|
bsc: {
|
|
31
21
|
chainId: 56,
|
|
32
22
|
serverUrl: 'https://bsc-clarity.a.exodus.io/',
|
|
@@ -146,7 +136,3 @@ export const CONFIRMATIONS_NUMBER = mapValues(
|
|
|
146
136
|
export const ETHEREUM_LIKE_ASSETS = Object.keys(CHAIN_DATA)
|
|
147
137
|
|
|
148
138
|
export const BUMP_RATE = 1.2
|
|
149
|
-
/* @deprecated */
|
|
150
|
-
export const ETHEREUM_LIKE_NO_HISTORY_ASSET_NAMES = Object.keys(CHAIN_DATA).filter(
|
|
151
|
-
(key) => CHAIN_DATA[key].monitorType === 'no-history'
|
|
152
|
-
)
|
|
@@ -1,24 +1,63 @@
|
|
|
1
1
|
import { Common, Hardfork } from '@exodus/ethereumjs/common'
|
|
2
2
|
import { FeeMarketEIP1559Transaction, Transaction } from '@exodus/ethereumjs/tx'
|
|
3
|
+
import { toBuffer } from '@exodus/ethereumjs/util'
|
|
4
|
+
import lodash from 'lodash'
|
|
5
|
+
import assert from 'minimalistic-assert'
|
|
6
|
+
|
|
7
|
+
const { isEmpty } = lodash
|
|
8
|
+
|
|
9
|
+
const parseBufferToJsTx = (unsignedTx) => {
|
|
10
|
+
const { transactionBuffer, ...legacyTxData } = unsignedTx.txData
|
|
11
|
+
assert(
|
|
12
|
+
isEmpty(legacyTxData),
|
|
13
|
+
'Cannot create ethereum js tx when transactionBuffer and other fields are provided!'
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if (FeeMarketEIP1559Transaction.isEip1559SerializedTx(transactionBuffer))
|
|
17
|
+
return FeeMarketEIP1559Transaction.fromSerializedTx(transactionBuffer)
|
|
18
|
+
return Transaction.fromSerializedTx(transactionBuffer)
|
|
19
|
+
}
|
|
3
20
|
|
|
4
21
|
export default function createEthereumJsTx(unsignedTx) {
|
|
5
22
|
const {
|
|
6
|
-
txData: {
|
|
7
|
-
txMeta: { eip1559Enabled },
|
|
23
|
+
txData: { transactionBuffer, ...legacyTxData },
|
|
8
24
|
} = unsignedTx
|
|
9
|
-
const { gasPrice, tipGasPrice } = txData
|
|
10
25
|
|
|
26
|
+
if (transactionBuffer) {
|
|
27
|
+
return parseBufferToJsTx(unsignedTx)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const {
|
|
31
|
+
chainId,
|
|
32
|
+
nonce: providedNonce,
|
|
33
|
+
gasPrice,
|
|
34
|
+
gasLimit: providedGasLimit,
|
|
35
|
+
tipGasPrice,
|
|
36
|
+
data: providedData,
|
|
37
|
+
value,
|
|
38
|
+
...txData
|
|
39
|
+
} = legacyTxData
|
|
40
|
+
|
|
41
|
+
const bufferData = toBuffer(providedData)
|
|
42
|
+
|
|
43
|
+
const gasLimit = toBuffer(providedGasLimit)
|
|
44
|
+
const data = bufferData.equals(Buffer.from([0])) ? Buffer.alloc(0) : bufferData
|
|
45
|
+
const nonce = providedNonce === 0 ? Buffer.alloc(0) : toBuffer(providedNonce)
|
|
11
46
|
/*
|
|
12
47
|
EIP1559 is not supported by all ethereum-like assets.
|
|
13
48
|
e.g BSC does not support EIP1559 at the moment, prevent building an EIP1559 transaction
|
|
14
49
|
if `tipGasPrice` or `maxPriorityFeePerGas` is set.
|
|
15
50
|
*/
|
|
16
51
|
const isEip1559Tx = !!(unsignedTx.txData.tipGasPrice || unsignedTx.txData.maxPriorityFeePerGas)
|
|
17
|
-
if (eip1559Enabled && isEip1559Tx) {
|
|
52
|
+
if (unsignedTx.txMeta.eip1559Enabled && isEip1559Tx) {
|
|
18
53
|
return FeeMarketEIP1559Transaction.fromTxData(
|
|
19
54
|
{
|
|
20
55
|
maxFeePerGas: gasPrice,
|
|
21
56
|
maxPriorityFeePerGas: tipGasPrice,
|
|
57
|
+
nonce,
|
|
58
|
+
gasLimit,
|
|
59
|
+
data,
|
|
60
|
+
value,
|
|
22
61
|
// `maxPriorityFeePerGas`, `maxFeePerGas` set in `txData` below take precedence over ^.
|
|
23
62
|
...txData,
|
|
24
63
|
},
|
|
@@ -34,5 +73,8 @@ export default function createEthereumJsTx(unsignedTx) {
|
|
|
34
73
|
}
|
|
35
74
|
|
|
36
75
|
// Legacy tx
|
|
37
|
-
return Transaction.fromTxData(
|
|
76
|
+
return Transaction.fromTxData(
|
|
77
|
+
{ nonce, gasPrice, tipGasPrice, gasLimit, data, value, ...txData },
|
|
78
|
+
{ common: Common.custom({ chainId }) }
|
|
79
|
+
)
|
|
38
80
|
}
|
|
@@ -1,34 +1,108 @@
|
|
|
1
|
+
import { FeeMarketEIP1559Transaction, Transaction } from '@exodus/ethereumjs/tx'
|
|
1
2
|
import { bufferToInt } from '@exodus/ethereumjs/util'
|
|
3
|
+
import lodash from 'lodash'
|
|
4
|
+
import assert from 'minimalistic-assert'
|
|
2
5
|
|
|
3
6
|
import { buffer2currency, isToken } from '../utils/index.js'
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
const { isEmpty } = lodash
|
|
9
|
+
|
|
10
|
+
const getCommonTransactionProps = ({ transaction, baseAsset }) => {
|
|
11
|
+
return {
|
|
12
|
+
data: transaction.data,
|
|
13
|
+
to: transaction.to.toString('hex'),
|
|
14
|
+
gasLimit: transaction.gasLimit.toNumber(),
|
|
15
|
+
value: baseAsset.currency.baseUnit(transaction.value),
|
|
16
|
+
nonce: transaction.nonce.toNumber(),
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const parseBuffer = (asset, unsignedTx) => {
|
|
21
|
+
const { transactionBuffer, ...legacyTxData } = unsignedTx.txData
|
|
8
22
|
const baseAsset = asset.baseAsset
|
|
9
|
-
|
|
10
|
-
|
|
23
|
+
assert(
|
|
24
|
+
isEmpty(legacyTxData),
|
|
25
|
+
'Cannot parse tx when transactionBuffer and other fields are provided!'
|
|
26
|
+
)
|
|
27
|
+
if (FeeMarketEIP1559Transaction.isEip1559SerializedTx(transactionBuffer)) {
|
|
28
|
+
const transaction = FeeMarketEIP1559Transaction.fromSerializedTx(transactionBuffer)
|
|
29
|
+
return {
|
|
30
|
+
...getCommonTransactionProps({ transaction, baseAsset }),
|
|
31
|
+
tipGasPrice: baseAsset.currency.baseUnit(transaction.maxPriorityFeePerGas),
|
|
32
|
+
gasPrice: baseAsset.currency.baseUnit(transaction.maxFeePerGas),
|
|
33
|
+
eip1559Enabled: true,
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const transaction = Transaction.fromSerializedTx(transactionBuffer)
|
|
38
|
+
return {
|
|
39
|
+
...getCommonTransactionProps({ transaction, baseAsset }),
|
|
40
|
+
gasPrice: baseAsset.currency.baseUnit(transaction.gasPrice),
|
|
41
|
+
eip1559Enabled: false,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function resolveToAmount({ asset, data, value, to: rawTo }) {
|
|
46
|
+
const _isToken = isToken(asset)
|
|
11
47
|
|
|
12
|
-
let { to, data, value } = txData
|
|
13
|
-
let amount
|
|
14
|
-
const fee = gasPrice.mul(gasLimit)
|
|
15
48
|
if (_isToken) {
|
|
16
49
|
const { method, values } = asset.contract.decodeInput(data)
|
|
17
|
-
if (method === 'transfer' || method === 'approve')
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
50
|
+
if (method === 'transfer' || method === 'approve')
|
|
51
|
+
return {
|
|
52
|
+
to: values[0],
|
|
53
|
+
amount: asset.currency.baseUnit(values[1]),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return { to: values[0], amount: asset.currency.ZERO }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
amount: value,
|
|
61
|
+
to: rawTo,
|
|
26
62
|
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default function parseUnsignedTx({ asset, unsignedTx }) {
|
|
66
|
+
assert(asset, 'asset is required')
|
|
67
|
+
assert(unsignedTx, 'unsignedTx is required')
|
|
68
|
+
const baseAsset = asset.baseAsset
|
|
69
|
+
const txData = unsignedTx.txData
|
|
70
|
+
const {
|
|
71
|
+
to: rawTo,
|
|
72
|
+
data,
|
|
73
|
+
value,
|
|
74
|
+
gasLimit,
|
|
75
|
+
gasPrice,
|
|
76
|
+
tipGasPrice,
|
|
77
|
+
eip1559Enabled,
|
|
78
|
+
nonce,
|
|
79
|
+
} = txData.transactionBuffer
|
|
80
|
+
? parseBuffer(asset, unsignedTx)
|
|
81
|
+
: {
|
|
82
|
+
data: txData.data,
|
|
83
|
+
to: txData.to,
|
|
84
|
+
value: buffer2currency({ asset: baseAsset, value: txData.value }),
|
|
85
|
+
gasPrice: buffer2currency({ asset: baseAsset, value: txData.gasPrice }),
|
|
86
|
+
tipGasPrice: txData.tipGasPrice
|
|
87
|
+
? buffer2currency({ asset: baseAsset, value: txData.tipGasPrice })
|
|
88
|
+
: undefined,
|
|
89
|
+
eip1559Enabled: Boolean(txData.tipGasPrice),
|
|
90
|
+
gasLimit: bufferToInt(txData.gasLimit),
|
|
91
|
+
nonce: bufferToInt(txData.nonce),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const fee = gasPrice.mul(gasLimit)
|
|
95
|
+
const { to, amount } = resolveToAmount({ asset, data, value, to: rawTo })
|
|
27
96
|
|
|
28
97
|
return {
|
|
29
98
|
to,
|
|
30
99
|
amount,
|
|
31
100
|
fee,
|
|
101
|
+
gasLimit,
|
|
102
|
+
gasPrice,
|
|
103
|
+
tipGasPrice,
|
|
104
|
+
eip1559Enabled,
|
|
105
|
+
nonce,
|
|
32
106
|
from: null, // TODO: how?
|
|
33
107
|
}
|
|
34
108
|
}
|
package/src/utils/index.js
CHANGED
|
@@ -2,9 +2,6 @@ import { FeeMarketEIP1559Transaction, Transaction } from '@exodus/ethereumjs/tx'
|
|
|
2
2
|
import { padToEven, toBuffer } from '@exodus/ethereumjs/util'
|
|
3
3
|
import baseX from 'base-x'
|
|
4
4
|
|
|
5
|
-
// eslint-disable-next-line @exodus/import/no-deprecated
|
|
6
|
-
import { ETHEREUM_LIKE_NO_HISTORY_ASSET_NAMES } from '../constants.js'
|
|
7
|
-
|
|
8
5
|
export { default as calculateExtraEth } from './calculate-extra-eth.js'
|
|
9
6
|
|
|
10
7
|
const base10 = baseX('0123456789')
|
|
@@ -13,12 +10,8 @@ const base16 = baseX('0123456789abcdef')
|
|
|
13
10
|
/* @deprecated */
|
|
14
11
|
export const isEthereumToken = (asset) => asset.assetType === 'ETHEREUM_ERC20'
|
|
15
12
|
/* @deprecated */
|
|
16
|
-
export const isEthereumGoerliToken = (asset) => asset.assetType === 'ETHEREUM_GOERLI_ERC20'
|
|
17
|
-
/* @deprecated */
|
|
18
13
|
export const isEthereumHoleskyToken = (asset) => asset.assetType === 'ETHEREUM_HOLESKY_ERC20'
|
|
19
14
|
/* @deprecated */
|
|
20
|
-
export const isEthereumSepoliaToken = (asset) => asset.assetType === 'ETHEREUM_SEPOLIA_ERC20'
|
|
21
|
-
/* @deprecated */
|
|
22
15
|
export const isBscToken = (asset) => asset.assetType === 'BSC_BEP20'
|
|
23
16
|
/* @deprecated */
|
|
24
17
|
export const isPolygonToken = (asset) => asset.assetType === 'MATIC_ERC20'
|
|
@@ -144,6 +137,7 @@ export const isRpcBalanceAsset = (asset) =>
|
|
|
144
137
|
[
|
|
145
138
|
'ethereumarbone',
|
|
146
139
|
'fantommainnet',
|
|
140
|
+
'basemainnet',
|
|
147
141
|
'matic',
|
|
148
142
|
'optimism',
|
|
149
143
|
'ousd_ethereum_48fcf72d',
|
|
@@ -151,7 +145,7 @@ export const isRpcBalanceAsset = (asset) =>
|
|
|
151
145
|
'weth',
|
|
152
146
|
...customTokensWithRpcBalance,
|
|
153
147
|
// eslint-disable-next-line @exodus/import/no-deprecated
|
|
154
|
-
].includes(asset.name)
|
|
148
|
+
].includes(asset.name)
|
|
155
149
|
|
|
156
150
|
export const getAssetAddresses = (asset) => {
|
|
157
151
|
// It seems to be two schemas of assets. The original and the transformed by the client.
|