Skip to content

Commit 3a36f44

Browse files
committed
add eip1559 settings to chainconfig
1 parent 8962307 commit 3a36f44

File tree

10 files changed

+667
-8
lines changed

10 files changed

+667
-8
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,31 @@ Implementation details:
269269
- No runtime environment variables are required; the chainspec carries the policy alongside other fork settings
270270
- When not configured, the EVM operates normally with standard fee burning
271271

272+
### Custom EIP-1559 Parameters (Custom Networks Only)
273+
274+
ev-reth also lets you override EIP-1559 base fee parameters through the same `evolve` stanza in
275+
your chainspec. This is consensus-critical: all nodes must use the same values.
276+
277+
```json
278+
"config": {
279+
...,
280+
"evolve": {
281+
"baseFeeMaxChangeDenominator": 8,
282+
"baseFeeElasticityMultiplier": 2,
283+
"initialBaseFeePerGas": 1000000000
284+
}
285+
}
286+
```
287+
288+
Notes:
289+
290+
- `baseFeeMaxChangeDenominator` and `baseFeeElasticityMultiplier` override the EIP-1559 formula.
291+
- `initialBaseFeePerGas` only applies when `londonBlock` is `0` (London at genesis). It updates the
292+
genesis `baseFeePerGas` value; if London is activated later, the initial base fee remains
293+
hardcoded to the EIP-1559 constant.
294+
- The node will fail fast if these values are invalid or inconsistent.
295+
- See `docs/eip1559-configuration.md` for recommended values at 100ms block times.
296+
272297
### Custom Contract Size Limit
273298

274299
By default, Ethereum enforces a 24KB contract size limit per [EIP-170](https://eips.ethereum.org/EIPS/eip-170). If your network requires larger contracts, `ev-reth` supports configuring a custom limit via the chainspec.

bin/ev-reth/src/main.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ use evolve_ev_reth::{
1010
config::EvolveConfig,
1111
rpc::txpool::{EvolveTxpoolApiImpl, EvolveTxpoolApiServer},
1212
};
13-
use reth_ethereum_cli::{chainspec::EthereumChainSpecParser, Cli};
13+
use reth_ethereum_cli::Cli;
1414
use reth_tracing_otlp::layer as otlp_layer;
1515
use tracing::info;
1616
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
1717

18-
use ev_node::{log_startup, EvolveArgs, EvolveNode};
18+
use ev_node::{log_startup, EvolveArgs, EvolveChainSpecParser, EvolveNode};
1919

2020
#[global_allocator]
2121
static ALLOC: reth_cli_util::allocator::Allocator = reth_cli_util::allocator::new_allocator();
@@ -47,8 +47,8 @@ fn main() {
4747
init_otlp_tracing();
4848
}
4949

50-
if let Err(err) = Cli::<EthereumChainSpecParser, EvolveArgs>::parse().run(
51-
|builder, _evolve_args| async move {
50+
if let Err(err) =
51+
Cli::<EvolveChainSpecParser, EvolveArgs>::parse().run(|builder, _evolve_args| async move {
5252
log_startup();
5353
let handle = builder
5454
.node(EvolveNode::new())
@@ -67,8 +67,8 @@ fn main() {
6767

6868
info!("=== EV-RETH: Node launched successfully with ev-reth payload builder ===");
6969
handle.node_exit_future.await
70-
},
71-
) {
70+
})
71+
{
7272
eprintln!("Error: {err:?}");
7373
std::process::exit(1);
7474
}
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.24;
3+
4+
import {Script, console} from "forge-std/Script.sol";
5+
import {FeeVault} from "../src/FeeVault.sol";
6+
7+
abstract contract FeeVaultAllocBase is Script {
8+
struct Config {
9+
address feeVaultAddress;
10+
address owner;
11+
uint32 destinationDomain;
12+
bytes32 recipientAddress;
13+
uint256 minimumAmount;
14+
uint256 callFee;
15+
uint256 bridgeShareBpsRaw;
16+
uint256 bridgeShareBps;
17+
address otherRecipient;
18+
address hypNativeMinter;
19+
bytes32 salt;
20+
address deployer;
21+
}
22+
23+
function loadConfig() internal view returns (Config memory cfg) {
24+
cfg.owner = vm.envAddress("OWNER");
25+
cfg.destinationDomain = uint32(vm.envOr("DESTINATION_DOMAIN", uint256(0)));
26+
cfg.recipientAddress = vm.envOr("RECIPIENT_ADDRESS", bytes32(0));
27+
cfg.minimumAmount = vm.envOr("MINIMUM_AMOUNT", uint256(0));
28+
cfg.callFee = vm.envOr("CALL_FEE", uint256(0));
29+
cfg.bridgeShareBpsRaw = vm.envOr("BRIDGE_SHARE_BPS", uint256(0));
30+
cfg.otherRecipient = vm.envOr("OTHER_RECIPIENT", address(0));
31+
cfg.hypNativeMinter = vm.envOr("HYP_NATIVE_MINTER", address(0));
32+
cfg.feeVaultAddress = vm.envOr("FEE_VAULT_ADDRESS", address(0));
33+
cfg.deployer = vm.envOr("DEPLOYER", address(0));
34+
cfg.salt = vm.envOr("SALT", bytes32(0));
35+
36+
require(cfg.owner != address(0), "OWNER required");
37+
require(cfg.bridgeShareBpsRaw <= 10000, "BRIDGE_SHARE_BPS > 10000");
38+
39+
cfg.bridgeShareBps = cfg.bridgeShareBpsRaw == 0 ? 10000 : cfg.bridgeShareBpsRaw;
40+
41+
if (cfg.feeVaultAddress == address(0) && cfg.deployer != address(0)) {
42+
bytes32 initCodeHash = keccak256(
43+
abi.encodePacked(
44+
type(FeeVault).creationCode,
45+
abi.encode(
46+
cfg.owner,
47+
cfg.destinationDomain,
48+
cfg.recipientAddress,
49+
cfg.minimumAmount,
50+
cfg.callFee,
51+
cfg.bridgeShareBpsRaw,
52+
cfg.otherRecipient
53+
)
54+
)
55+
);
56+
cfg.feeVaultAddress =
57+
address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), cfg.deployer, cfg.salt, initCodeHash)))));
58+
}
59+
60+
require(cfg.feeVaultAddress != address(0), "FEE_VAULT_ADDRESS or DEPLOYER required");
61+
}
62+
63+
function computeSlots(Config memory cfg)
64+
internal
65+
pure
66+
returns (
67+
bytes32 slot0,
68+
bytes32 slot1,
69+
bytes32 slot2,
70+
bytes32 slot3,
71+
bytes32 slot4,
72+
bytes32 slot5,
73+
bytes32 slot6
74+
)
75+
{
76+
slot0 = bytes32(uint256(uint160(cfg.hypNativeMinter)));
77+
slot1 = bytes32((uint256(cfg.destinationDomain) << 160) | uint256(uint160(cfg.owner)));
78+
slot2 = cfg.recipientAddress;
79+
slot3 = bytes32(cfg.minimumAmount);
80+
slot4 = bytes32(cfg.callFee);
81+
slot5 = bytes32(uint256(uint160(cfg.otherRecipient)));
82+
slot6 = bytes32(cfg.bridgeShareBps);
83+
}
84+
85+
function addressKey(address addr) internal pure returns (string memory) {
86+
bytes memory full = bytes(vm.toString(addr));
87+
bytes memory key = new bytes(40);
88+
// Fixed-length copy for address key without 0x prefix.
89+
for (uint256 i = 0; i < 40; i++) {
90+
key[i] = full[i + 2];
91+
}
92+
return string(key);
93+
}
94+
}
95+
96+
/// @title GenerateFeeVaultAlloc
97+
/// @notice Generates genesis alloc JSON for deploying FeeVault at a deterministic address
98+
/// @dev Run with: OWNER=0x... forge script script/GenerateFeeVaultAlloc.s.sol -vvv
99+
contract GenerateFeeVaultAlloc is FeeVaultAllocBase {
100+
function run() external view {
101+
Config memory cfg = loadConfig();
102+
bytes memory runtimeCode = type(FeeVault).runtimeCode;
103+
104+
(
105+
bytes32 slot0,
106+
bytes32 slot1,
107+
bytes32 slot2,
108+
bytes32 slot3,
109+
bytes32 slot4,
110+
bytes32 slot5,
111+
bytes32 slot6
112+
) = computeSlots(cfg);
113+
114+
console.log("========== FeeVault Genesis Alloc ==========");
115+
console.log("FeeVault address:", cfg.feeVaultAddress);
116+
console.log("Owner:", cfg.owner);
117+
console.log("Destination domain:", cfg.destinationDomain);
118+
console.log("Bridge share bps (raw):", cfg.bridgeShareBpsRaw);
119+
console.log("Bridge share bps (effective):", cfg.bridgeShareBps);
120+
console.log("");
121+
122+
if (cfg.bridgeShareBpsRaw == 0) {
123+
console.log("NOTE: BRIDGE_SHARE_BPS=0 defaults to 10000 (constructor behavior).");
124+
}
125+
if (cfg.bridgeShareBps < 10000 && cfg.otherRecipient == address(0)) {
126+
console.log("WARNING: OTHER_RECIPIENT is zero but bridge share < 10000.");
127+
}
128+
if (cfg.hypNativeMinter == address(0)) {
129+
console.log("NOTE: HYP_NATIVE_MINTER is zero; set it before calling sendToCelestia().");
130+
}
131+
console.log("");
132+
133+
console.log("Add this to your genesis.json 'alloc' section:");
134+
console.log("");
135+
console.log("{");
136+
console.log(' "alloc": {');
137+
console.log(' "%s": {', addressKey(cfg.feeVaultAddress));
138+
console.log(' "balance": "0x0",');
139+
console.log(' "code": "0x%s",', vm.toString(runtimeCode));
140+
console.log(' "storage": {');
141+
console.log(' "0x0": "0x%s",', vm.toString(slot0));
142+
console.log(' "0x1": "0x%s",', vm.toString(slot1));
143+
console.log(' "0x2": "0x%s",', vm.toString(slot2));
144+
console.log(' "0x3": "0x%s",', vm.toString(slot3));
145+
console.log(' "0x4": "0x%s",', vm.toString(slot4));
146+
console.log(' "0x5": "0x%s",', vm.toString(slot5));
147+
console.log(' "0x6": "0x%s"', vm.toString(slot6));
148+
console.log(" }");
149+
console.log(" }");
150+
console.log(" }");
151+
console.log("}");
152+
console.log("");
153+
console.log("Raw bytecode length:", runtimeCode.length);
154+
console.log("=============================================");
155+
}
156+
}
157+
158+
/// @title GenerateFeeVaultAllocJSON
159+
/// @notice Outputs just the JSON snippet for easy copy-paste
160+
/// @dev Run with: OWNER=0x... forge script script/GenerateFeeVaultAlloc.s.sol:GenerateFeeVaultAllocJSON -vvv
161+
contract GenerateFeeVaultAllocJSON is FeeVaultAllocBase {
162+
function run() external view {
163+
Config memory cfg = loadConfig();
164+
bytes memory runtimeCode = type(FeeVault).runtimeCode;
165+
166+
(
167+
bytes32 slot0,
168+
bytes32 slot1,
169+
bytes32 slot2,
170+
bytes32 slot3,
171+
bytes32 slot4,
172+
bytes32 slot5,
173+
bytes32 slot6
174+
) = computeSlots(cfg);
175+
176+
string memory json = string(
177+
abi.encodePacked(
178+
'{"',
179+
addressKey(cfg.feeVaultAddress),
180+
'":{"balance":"0x0","code":"0x',
181+
vm.toString(runtimeCode),
182+
'","storage":{"0x0":"0x',
183+
vm.toString(slot0),
184+
'","0x1":"0x',
185+
vm.toString(slot1),
186+
'","0x2":"0x',
187+
vm.toString(slot2),
188+
'","0x3":"0x',
189+
vm.toString(slot3),
190+
'","0x4":"0x',
191+
vm.toString(slot4),
192+
'","0x5":"0x',
193+
vm.toString(slot5),
194+
'","0x6":"0x',
195+
vm.toString(slot6),
196+
'"}}}'
197+
)
198+
);
199+
200+
console.log(json);
201+
}
202+
}

crates/node/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ ev-revm = { path = "../ev-revm" }
1717
# Reth dependencies
1818
reth-node-builder.workspace = true
1919
reth-chainspec.workspace = true
20+
reth-cli.workspace = true
2021
reth-ethereum = { workspace = true, features = ["node", "cli", "pool"] }
2122
reth-ethereum-forks.workspace = true
2223
reth-ethereum-payload-builder.workspace = true
@@ -52,6 +53,7 @@ alloy-primitives.workspace = true
5253
alloy-eips.workspace = true
5354
alloy-consensus.workspace = true
5455
alloy-evm.workspace = true
56+
alloy-genesis.workspace = true
5557

5658
# Core dependencies
5759
eyre.workspace = true
@@ -73,7 +75,6 @@ reth-transaction-pool.workspace = true
7375
reth-consensus.workspace = true
7476
reth-tasks.workspace = true
7577
reth-tracing.workspace = true
76-
alloy-genesis.workspace = true
7778
tempfile.workspace = true
7879
hex = "0.4"
7980

0 commit comments

Comments
 (0)