@exodus/ethereum-lib 5.20.0 → 5.20.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,16 @@
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.20.1](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-lib@5.20.0...@exodus/ethereum-lib@5.20.1) (2025-12-09)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+
12
+ * fix: EIP1559 acceleration gas calculation in (#6997). Update getLinearIncentiveBumpForEip1559Transaction() to properly calculate bump tx logic under eip1559
13
+
14
+
15
+
6
16
  ## [5.20.0](https://github.com/ExodusMovement/assets/compare/@exodus/ethereum-lib@5.18.5...@exodus/ethereum-lib@5.20.0) (2025-11-19)
7
17
 
8
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/ethereum-lib",
3
- "version": "5.20.0",
3
+ "version": "5.20.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",
@@ -51,5 +51,5 @@
51
51
  "type": "git",
52
52
  "url": "git+https://github.com/ExodusMovement/assets.git"
53
53
  },
54
- "gitHead": "a15d8239871e44fd99d48a2b1a66606e2d428735"
54
+ "gitHead": "727e0bc0ae5bde63d522d618fc14ff7701fdb156"
55
55
  }
package/src/constants.js CHANGED
@@ -136,3 +136,6 @@ export const CONFIRMATIONS_NUMBER = mapValues(
136
136
  export const ETHEREUM_LIKE_ASSETS = Object.keys(CHAIN_DATA)
137
137
 
138
138
  export const BUMP_RATE = 1.2
139
+ // Node bump requirement (10% as enforced by Geth/Erigon/Nethermind)
140
+ // Client always bumps by 20% (BUMP_RATE) to exceed this threshold
141
+ export const NODE_BUMP_REQUIREMENT = 1.1
@@ -103,37 +103,63 @@ const calculateBumpedGasPriceNonEip1559 = ({ currentGasPrice, prevMaxFeePerGas }
103
103
  }
104
104
  }
105
105
 
106
- const getLinearIncentiveBumpForEip1559Transaction = ({
106
+ /*
107
+ Node Rules:
108
+ GETH:
109
+ The EIP1559 transaction bump logic requires that a replacement transaction must have BOTH:
110
+ 1. GasFeeCap >= oldGasFeeCap × (100 + priceBump) / 100
111
+ 2. GasTipCap >= oldGasTipCap × (100 + priceBump) / 100
112
+ ERIGON:
113
+ The Erigon EIP1559 transaction bump logic requires that a replacement transaction must have BOTH:
114
+ 1. `Tip >= oldTip × (100 + priceBump) / 100`
115
+ 2. `FeeCap >= oldFeeCap × (100 + priceBump) / 100`
116
+ NETHERMIND:
117
+ Nethermind's EIP1559 transaction bump logic requires that a replacement transaction must have BOTH:
118
+ ### Regular Transactions (10% bump)
119
+ 1. `newMaxFeePerGas > oldMaxFeePerGas × 1.1`
120
+ 2. `newMaxPriorityFeePerGas > oldMaxPriorityFeePerGas × 1.1`
121
+
122
+ In short, all these 3 nodes require that the bump is applied to both the tip and the cap.
123
+ This won't work for besu nodes.
124
+ */
125
+ export const getLinearIncentiveBumpForEip1559Transaction = ({
107
126
  currentBaseFeePerGas,
108
- prevMaxFeePerGas,
109
- prevMaxPriorityFeePerGas,
127
+ prevMaxFeePerGas, // Previous maxFeePerGas (includes the old tip)
128
+ prevMaxPriorityFeePerGas, // Previous tip (maxPriorityFeePerGas)
110
129
  }) => {
111
130
  assert(currentBaseFeePerGas, 'currentBaseFeePerGas is required')
112
131
  assert(prevMaxFeePerGas, 'prevMaxFeePerGas is required')
113
132
  assert(prevMaxPriorityFeePerGas, 'prevMaxPriorityFeePerGas is required')
114
133
 
115
- // First, let's determine if there's a bump required just to bring
116
- // the transaction up to the `baseFeePerGas`. If the current base
117
- // fee is larger, we'll need to see how much to adjust the overall
118
- // transaction by.
119
- const increaseToBaseFeePerGasTipGasPrice = currentBaseFeePerGas.gt(prevMaxFeePerGas)
120
- ? currentBaseFeePerGas.sub(prevMaxFeePerGas)
121
- : currentBaseFeePerGas.sub(currentBaseFeePerGas) // TODO: What is a nice way to get ZERO without an `asset`? Is it `currentBaseFeePerGas.ZERO`?
122
-
123
- // The new `bumpedTipGasPrice`.
124
- const bumpedTipGasPrice = prevMaxPriorityFeePerGas
125
- .mul(BUMP_RATE)
126
- .add(increaseToBaseFeePerGasTipGasPrice)
127
-
128
- // We'll make attempt a linear increase of the transaction pricing. By
129
- // increasing the `tipGasPrice` and the `gasPrice` by the same amount,
130
- // we ensuret he any additional amount we spend (over the basefee) goes
131
- // directly to the miner, thereby increasing transaction incentive.
134
+ //
135
+ // ---- STEP 1: Geth / Erigon / Nethermind "pricebump" policy ----
136
+ //
137
+ // These clients require that BOTH the tip AND the cap are bumped by
138
+ // the configured percentage (BUMP_RATE), compared to the previous tx:
139
+ //
140
+ // newTip >= prevTip * BUMP_RATE AND
141
+ // newMaxFee >= prevMaxFee * BUMP_RATE
142
+ //
143
+ // Both conditions must be satisfied independently for the replacement
144
+ // transaction to be accepted by the node's mempool.
145
+ //
146
+ const newTip = prevMaxPriorityFeePerGas.mul(BUMP_RATE)
147
+ let newMaxFee = prevMaxFeePerGas.mul(BUMP_RATE)
148
+
149
+ //
150
+ // ---- STEP 2: EIP-1559 validity "now" ----
151
+ //
152
+ // EIP-1559 requires maxFeePerGas >= baseFee + tip for the tx
153
+ // to be able to actually pay the full priority fee at the current baseFee.
154
+ //
155
+ const minCapRequiredNow = currentBaseFeePerGas.add(newTip)
156
+ if (newMaxFee.lt(minCapRequiredNow)) {
157
+ newMaxFee = minCapRequiredNow
158
+ }
159
+
132
160
  return {
133
- bumpedGasPrice: prevMaxFeePerGas
134
- .sub(prevMaxPriorityFeePerGas) // Removes the previous `tipGasPrice` before adding the next one (`bumpedTipGasPrice` is inclusive).
135
- .add(bumpedTipGasPrice),
136
- bumpedTipGasPrice,
161
+ bumpedGasPrice: newMaxFee,
162
+ bumpedTipGasPrice: newTip,
137
163
  }
138
164
  }
139
165