@exodus/ethereum-lib 5.18.0 → 5.18.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 CHANGED
@@ -3,6 +3,14 @@
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.18.1](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-lib@5.18.0...@exodus/ethereum-lib@5.18.1) (2025-10-02)
7
+
8
+ **Note:** Version bump only for package @exodus/ethereum-lib
9
+
10
+
11
+
12
+
13
+
6
14
  ## [5.18.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-lib@5.17.3...@exodus/ethereum-lib@5.18.0) (2025-09-26)
7
15
 
8
16
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/ethereum-lib",
3
- "version": "5.18.0",
3
+ "version": "5.18.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",
@@ -50,5 +50,5 @@
50
50
  "type": "git",
51
51
  "url": "git+https://github.com/ExodusMovement/assets.git"
52
52
  },
53
- "gitHead": "cf881908a1cff88e98d2f9a7a3f29357474e3d0c"
53
+ "gitHead": "f6ea2714c95f2e7ec71ffecdc589726b7974511e"
54
54
  }
@@ -6,6 +6,59 @@ import assert from 'minimalistic-assert'
6
6
 
7
7
  const { isEmpty } = lodash
8
8
 
9
+ const getEthereumJsTxDefsByEip1559 = ({ eip1559Enabled }) => {
10
+ assert(typeof eip1559Enabled === 'boolean', 'expected eip1559Enabled')
11
+
12
+ const EthereumJsTransactionClass = eip1559Enabled ? FeeMarketEIP1559Transaction : Transaction
13
+ const hardfork = eip1559Enabled ? Hardfork.London : Hardfork.Istanbul
14
+
15
+ return { EthereumJsTransactionClass, hardfork }
16
+ }
17
+
18
+ const getEthereumJsTxDefsByTransactionBuffer = ({ transactionBuffer }) => {
19
+ assert(Buffer.isBuffer(transactionBuffer), 'expected Buffer transactionBuffer')
20
+
21
+ return getEthereumJsTxDefsByEip1559({
22
+ eip1559Enabled: FeeMarketEIP1559Transaction.isEip1559SerializedTx(transactionBuffer),
23
+ })
24
+ }
25
+
26
+ const getEthereumJsTxCommon = ({ chainId, ethereumJsTxDefs }) => {
27
+ assert(ethereumJsTxDefs, 'expected ethereumJsTxDefs')
28
+
29
+ const { hardfork } = ethereumJsTxDefs
30
+
31
+ return Common.custom(
32
+ ...[typeof chainId === 'number' && { chainId }, { hardfork }].filter(Boolean)
33
+ )
34
+ }
35
+
36
+ export const getEthereumJsTxByTransactionBuffer = ({ chainId, transactionBuffer }) => {
37
+ assert(typeof chainId === 'number', 'expected chainId')
38
+
39
+ const ethereumJsTxDefs = getEthereumJsTxDefsByTransactionBuffer({ transactionBuffer })
40
+ const { EthereumJsTransactionClass } = ethereumJsTxDefs
41
+
42
+ return EthereumJsTransactionClass.fromSerializedTx(transactionBuffer, {
43
+ common: getEthereumJsTxCommon({ chainId, ethereumJsTxDefs }),
44
+ })
45
+ }
46
+
47
+ export const getEthereumJsTxByTransactionProps = ({
48
+ chainId,
49
+ eip1559Enabled = false,
50
+ transactionProps,
51
+ }) => {
52
+ assert(typeof chainId === 'number', 'expected chainId')
53
+
54
+ const ethereumJsTxDefs = getEthereumJsTxDefsByEip1559({ eip1559Enabled })
55
+ const { EthereumJsTransactionClass } = ethereumJsTxDefs
56
+
57
+ return EthereumJsTransactionClass.fromTxData(transactionProps, {
58
+ common: getEthereumJsTxCommon({ chainId, ethereumJsTxDefs }),
59
+ })
60
+ }
61
+
9
62
  const parseBufferToJsTx = (unsignedTx) => {
10
63
  const { transactionBuffer, chainId, ...legacyTxData } = unsignedTx.txData
11
64
  assert(
@@ -13,21 +66,10 @@ const parseBufferToJsTx = (unsignedTx) => {
13
66
  'Cannot create ethereum js tx when transactionBuffer and other fields are provided!'
14
67
  )
15
68
  assert(chainId, 'chainId must be provided when parsing from transaction buffer!!!')
16
- if (FeeMarketEIP1559Transaction.isEip1559SerializedTx(transactionBuffer)) {
17
- return FeeMarketEIP1559Transaction.fromSerializedTx(transactionBuffer, {
18
- common: Common.custom(
19
- {
20
- chainId,
21
- },
22
- { hardfork: Hardfork.London }
23
- ),
24
- })
25
- }
26
69
 
27
- return Transaction.fromSerializedTx(transactionBuffer, {
28
- common: Common.custom({
29
- chainId,
30
- }),
70
+ return getEthereumJsTxByTransactionBuffer({
71
+ transactionBuffer,
72
+ chainId,
31
73
  })
32
74
  }
33
75
 
@@ -36,58 +78,77 @@ export default function createEthereumJsTx(unsignedTx) {
36
78
  txData: { transactionBuffer, ...legacyTxData },
37
79
  } = unsignedTx
38
80
 
39
- if (transactionBuffer) {
40
- return parseBufferToJsTx(unsignedTx)
41
- }
81
+ if (transactionBuffer) return parseBufferToJsTx(unsignedTx)
42
82
 
43
83
  const {
44
84
  chainId,
45
85
  nonce: providedNonce,
46
- gasPrice,
47
86
  gasLimit: providedGasLimit,
48
- tipGasPrice,
49
87
  data: providedData,
50
- value,
88
+
89
+ /* exodus eip1559 */
90
+ gasPrice,
91
+ tipGasPrice,
92
+
93
+ /* web3 eip1559 */
94
+ // NOTE: In Web3 EIP-1559, `maxFeePerGas` is mandatory, whilst
95
+ // `maxPriorityFeePerGas` can default to zero. If a third
96
+ // party transaction intends to do EIP-1559, they *must*
97
+ // have defined a `maxFeePerGas`.
98
+ maxFeePerGas,
99
+ maxPriorityFeePerGas,
100
+
51
101
  ...txData
52
102
  } = legacyTxData
53
103
 
54
104
  const bufferData = toBuffer(providedData)
55
-
56
105
  const gasLimit = toBuffer(providedGasLimit)
57
106
  const data = bufferData.equals(Buffer.from([0])) ? Buffer.alloc(0) : bufferData
58
107
  const nonce = providedNonce === 0 ? Buffer.alloc(0) : toBuffer(providedNonce)
59
- /*
60
- EIP1559 is not supported by all ethereum-like assets.
61
- e.g BSC does not support EIP1559 at the moment, prevent building an EIP1559 transaction
62
- if `tipGasPrice` or `maxPriorityFeePerGas` is set.
63
- */
64
- const isEip1559Tx = !!(unsignedTx.txData.tipGasPrice || unsignedTx.txData.maxPriorityFeePerGas)
65
- if (unsignedTx.txMeta.eip1559Enabled && isEip1559Tx) {
66
- return FeeMarketEIP1559Transaction.fromTxData(
67
- {
68
- maxFeePerGas: gasPrice,
69
- maxPriorityFeePerGas: tipGasPrice,
70
- nonce,
71
- gasLimit,
72
- data,
73
- value,
74
- // `maxPriorityFeePerGas`, `maxFeePerGas` set in `txData` below take precedence over ^.
75
- ...txData,
76
- },
77
- {
78
- common: Common.custom(
79
- {
80
- chainId,
81
- },
82
- { hardfork: Hardfork.London }
83
- ),
84
- }
85
- )
108
+
109
+ const commonTransactionProps = {
110
+ ...txData,
111
+ nonce,
112
+ gasLimit,
113
+ data,
86
114
  }
87
115
 
88
- // Legacy tx
89
- return Transaction.fromTxData(
90
- { nonce, gasPrice, tipGasPrice, gasLimit, data, value, ...txData },
91
- { common: Common.custom({ chainId }) }
92
- )
116
+ const createNonEip1559Transaction = () => {
117
+ assert(gasPrice, 'expected gasPrice')
118
+
119
+ return getEthereumJsTxByTransactionProps({
120
+ chainId,
121
+ transactionProps: { ...commonTransactionProps, gasPrice },
122
+ })
123
+ }
124
+
125
+ // If a non-EIP-1559 style transaction has been supplied,
126
+ // then create a legacy trasaction.
127
+ if (!unsignedTx.txMeta.eip1559Enabled) return createNonEip1559Transaction()
128
+
129
+ // Internally, Exodus uses the convention that an EIP-1559
130
+ // transaction must use `gasPrice` and `tipGasPrice`. Web3
131
+ // can provide a `maxFeePerGas` and optional
132
+ // `maxPriorityFeePerGas`.
133
+ //
134
+ // Likewise, if a `maxFeePerGas` has been omitted, the
135
+ // transaction *must* have defined a `gasPrice`.
136
+ if (tipGasPrice || !maxFeePerGas) assert(gasPrice, 'expected gasPrice')
137
+
138
+ // If neither properties were truthy, attempt to construct
139
+ // a legacy transaction.
140
+ if (!(tipGasPrice || maxFeePerGas)) return createNonEip1559Transaction()
141
+
142
+ // Create an EIP-1559 style transaction.
143
+ return getEthereumJsTxByTransactionProps({
144
+ chainId,
145
+ eip1559Enabled: true,
146
+ transactionProps: {
147
+ ...commonTransactionProps,
148
+ // NOTE: Here we force the appropriate conventions for gas.
149
+ ...(maxFeePerGas
150
+ ? { maxFeePerGas, maxPriorityFeePerGas } /* web3 */
151
+ : { maxFeePerGas: gasPrice, maxPriorityFeePerGas: tipGasPrice }) /* exodus */,
152
+ },
153
+ })
93
154
  }
@@ -2,6 +2,10 @@ export { default as createUnsignedTxFactory } from './create-unsigned-tx.js'
2
2
  export { default as parseUnsignedTx } from './parse-unsigned-tx.js'
3
3
  export { default as signUnsignedTx, signUnsignedTxWithSigner } from './sign-unsigned-tx.js'
4
4
  export { default as createAndSignTxFactory } from './create-and-sign-tx.js'
5
- export { default as createEthereumJsTx } from './create-ethereumjs-tx.js'
5
+ export {
6
+ default as createEthereumJsTx,
7
+ getEthereumJsTxByTransactionBuffer,
8
+ getEthereumJsTxByTransactionProps,
9
+ } from './create-ethereumjs-tx.js'
6
10
  export { signHardwareFactory } from './sign-hardware.js'
7
11
  export { default as updateNonce } from './update-nonce.js'
@@ -1,16 +1,22 @@
1
- import { FeeMarketEIP1559Transaction, Transaction } from '@exodus/ethereumjs/tx'
1
+ import assert from 'minimalistic-assert'
2
2
 
3
- const updateNonce = (transactionBuffer, newNonce) => {
4
- if (FeeMarketEIP1559Transaction.isEip1559SerializedTx(transactionBuffer)) {
5
- const transaction = FeeMarketEIP1559Transaction.fromSerializedTx(transactionBuffer)
6
- return FeeMarketEIP1559Transaction.fromTxData({
7
- ...transaction.toJSON(),
8
- nonce: newNonce,
9
- }).serialize()
10
- }
3
+ import { getEthereumJsTxByTransactionBuffer } from './create-ethereumjs-tx.js'
11
4
 
12
- const transaction = Transaction.fromSerializedTx(transactionBuffer)
13
- return Transaction.fromTxData({ ...transaction.toJSON(), nonce: newNonce }).serialize()
5
+ const updateNonce = ({ chainId, transactionBuffer, newNonce }) => {
6
+ assert(Buffer.isBuffer(transactionBuffer), 'expected Buffer transactionBuffer')
7
+ assert(typeof newNonce === 'number', 'expected number newNonce')
8
+ assert(typeof chainId === 'number', 'expected number chainId')
9
+
10
+ const transaction = getEthereumJsTxByTransactionBuffer({
11
+ chainId,
12
+ transactionBuffer,
13
+ })
14
+
15
+ // NOTE: Here we use the `static` `fromTxData` function via
16
+ // the `transaction` instance.
17
+ return transaction.constructor
18
+ .fromTxData({ ...transaction.toJSON(), nonce: newNonce })
19
+ .serialize()
14
20
  }
15
21
 
16
22
  export default updateNonce