@exodus/ethereum-lib 5.12.0 → 5.13.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 +12 -0
- package/package.json +3 -3
- package/src/constants.js +0 -10
- 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 +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
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.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-lib@5.12.0...@exodus/ethereum-lib@5.13.0) (2025-06-18)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* feat: allow transactionBuffer in unsignedTx (#5883)
|
|
13
|
+
|
|
14
|
+
* feat: remove eth sepolia and goerli (#5885)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
6
18
|
## [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
19
|
|
|
8
20
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/ethereum-lib",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.13.0",
|
|
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": "4c871b4f5c3ed6a503547eb1b749a746770d2e5f"
|
|
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/',
|
|
@@ -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
|
@@ -13,12 +13,8 @@ const base16 = baseX('0123456789abcdef')
|
|
|
13
13
|
/* @deprecated */
|
|
14
14
|
export const isEthereumToken = (asset) => asset.assetType === 'ETHEREUM_ERC20'
|
|
15
15
|
/* @deprecated */
|
|
16
|
-
export const isEthereumGoerliToken = (asset) => asset.assetType === 'ETHEREUM_GOERLI_ERC20'
|
|
17
|
-
/* @deprecated */
|
|
18
16
|
export const isEthereumHoleskyToken = (asset) => asset.assetType === 'ETHEREUM_HOLESKY_ERC20'
|
|
19
17
|
/* @deprecated */
|
|
20
|
-
export const isEthereumSepoliaToken = (asset) => asset.assetType === 'ETHEREUM_SEPOLIA_ERC20'
|
|
21
|
-
/* @deprecated */
|
|
22
18
|
export const isBscToken = (asset) => asset.assetType === 'BSC_BEP20'
|
|
23
19
|
/* @deprecated */
|
|
24
20
|
export const isPolygonToken = (asset) => asset.assetType === 'MATIC_ERC20'
|