diff --git a/Cargo.lock b/Cargo.lock index ef8c2de..1660824 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2937,6 +2937,7 @@ dependencies = [ "alloy-primitives", "alloy-signer-local", "clap", + "ev-deployer", "ev-node", "evolve-ev-reth", "eyre", diff --git a/bin/ev-deployer/src/config.rs b/bin/ev-deployer/src/config.rs index bf1f867..896155b 100644 --- a/bin/ev-deployer/src/config.rs +++ b/bin/ev-deployer/src/config.rs @@ -7,7 +7,7 @@ use std::path::Path; /// Top-level deploy configuration. #[derive(Debug, Deserialize)] #[allow(dead_code)] -pub(crate) struct DeployConfig { +pub struct DeployConfig { /// Chain configuration. pub chain: ChainConfig, /// Contract configurations. @@ -18,14 +18,14 @@ pub(crate) struct DeployConfig { /// Chain-level settings. #[derive(Debug, Deserialize)] #[allow(dead_code)] -pub(crate) struct ChainConfig { +pub struct ChainConfig { /// The chain ID. pub chain_id: u64, } /// All contract configurations. #[derive(Debug, Deserialize, Default)] -pub(crate) struct ContractsConfig { +pub struct ContractsConfig { /// `AdminProxy` contract config (optional). pub admin_proxy: Option, /// `Permit2` contract config (optional). @@ -34,7 +34,7 @@ pub(crate) struct ContractsConfig { /// `AdminProxy` configuration. #[derive(Debug, Deserialize)] -pub(crate) struct AdminProxyConfig { +pub struct AdminProxyConfig { /// Address to deploy at. pub address: Address, /// Owner address. @@ -43,14 +43,14 @@ pub(crate) struct AdminProxyConfig { /// `Permit2` configuration (Uniswap token approval manager). #[derive(Debug, Deserialize)] -pub(crate) struct Permit2Config { +pub struct Permit2Config { /// Address to deploy at. pub address: Address, } impl DeployConfig { /// Load and validate config from a TOML file. - pub(crate) fn load(path: &Path) -> eyre::Result { + pub fn load(path: &Path) -> eyre::Result { let content = std::fs::read_to_string(path)?; let config: Self = toml::from_str(&content)?; config.validate()?; diff --git a/bin/ev-deployer/src/contracts/admin_proxy.rs b/bin/ev-deployer/src/contracts/admin_proxy.rs index ed187b1..2cedfcd 100644 --- a/bin/ev-deployer/src/contracts/admin_proxy.rs +++ b/bin/ev-deployer/src/contracts/admin_proxy.rs @@ -9,7 +9,7 @@ use std::collections::BTreeMap; const ADMIN_PROXY_BYTECODE: &[u8] = &hex!("60806040526004361061007e575f3560e01c80638da5cb5b1161004d5780638da5cb5b1461012d578063e30c397814610157578063f2fde38b14610181578063fa4bb79d146101a957610085565b806318dfb3c7146100895780631cff79cd146100c557806379ba5097146101015780638b5298541461011757610085565b3661008557005b5f5ffd5b348015610094575f5ffd5b506100af60048036038101906100aa9190610cf8565b6101e5565b6040516100bc9190610ea1565b60405180910390f35b3480156100d0575f5ffd5b506100eb60048036038101906100e69190610f70565b6104d9565b6040516100f89190611015565b60405180910390f35b34801561010c575f5ffd5b5061011561066c565b005b348015610122575f5ffd5b5061012b6107ed565b005b348015610138575f5ffd5b506101416108b4565b60405161014e9190611044565b60405180910390f35b348015610162575f5ffd5b5061016b6108d8565b6040516101789190611044565b60405180910390f35b34801561018c575f5ffd5b506101a760048036038101906101a2919061105d565b6108fd565b005b3480156101b4575f5ffd5b506101cf60048036038101906101ca91906110bb565b610aa4565b6040516101dc9190611015565b60405180910390f35b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026c576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282905085859050146102ab576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484905067ffffffffffffffff8111156102c8576102c761112c565b5b6040519080825280602002602001820160405280156102fb57816020015b60608152602001906001900390816102e65790505b5090505f5f90505b858590508110156104d0575f5f87878481811061032357610322611159565b5b9050602002016020810190610338919061105d565b73ffffffffffffffffffffffffffffffffffffffff1686868581811061036157610360611159565b5b90506020028101906103739190611192565b604051610381929190611230565b5f604051808303815f865af19150503d805f81146103ba576040519150601f19603f3d011682016040523d82523d5f602084013e6103bf565b606091505b50915091508161040657806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016103fd9190611015565b60405180910390fd5b87878481811061041957610418611159565b5b905060200201602081019061042e919061105d565b73ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb587878681811061047857610477611159565b5b905060200281019061048a9190611192565b8460405161049a93929190611274565b60405180910390a2808484815181106104b6576104b5611159565b5b602002602001018190525050508080600101915050610303565b50949350505050565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610560576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8573ffffffffffffffffffffffffffffffffffffffff168585604051610589929190611230565b5f604051808303815f865af19150503d805f81146105c2576040519150601f19603f3d011682016040523d82523d5f602084013e6105c7565b606091505b50915091508161060e57806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016106059190611015565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb586868460405161065893929190611274565b60405180910390a280925050509392505050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106f2576040517f1853971c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3335f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610872576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610982576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036109e7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b2b576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff16848787604051610b55929190611230565b5f6040518083038185875af1925050503d805f8114610b8f576040519150601f19603f3d011682016040523d82523d5f602084013e610b94565b606091505b509150915081610bdb57806040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152600401610bd29190611015565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb5878784604051610c2593929190611274565b60405180910390a28092505050949350505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112610c6357610c62610c42565b5b8235905067ffffffffffffffff811115610c8057610c7f610c46565b5b602083019150836020820283011115610c9c57610c9b610c4a565b5b9250929050565b5f5f83601f840112610cb857610cb7610c42565b5b8235905067ffffffffffffffff811115610cd557610cd4610c46565b5b602083019150836020820283011115610cf157610cf0610c4a565b5b9250929050565b5f5f5f5f60408587031215610d1057610d0f610c3a565b5b5f85013567ffffffffffffffff811115610d2d57610d2c610c3e565b5b610d3987828801610c4e565b9450945050602085013567ffffffffffffffff811115610d5c57610d5b610c3e565b5b610d6887828801610ca3565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610de182610d9f565b610deb8185610da9565b9350610dfb818560208601610db9565b610e0481610dc7565b840191505092915050565b5f610e1a8383610dd7565b905092915050565b5f602082019050919050565b5f610e3882610d76565b610e428185610d80565b935083602082028501610e5485610d90565b805f5b85811015610e8f5784840389528151610e708582610e0f565b9450610e7b83610e22565b925060208a01995050600181019050610e57565b50829750879550505050505092915050565b5f6020820190508181035f830152610eb98184610e2e565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610eea82610ec1565b9050919050565b610efa81610ee0565b8114610f04575f5ffd5b50565b5f81359050610f1581610ef1565b92915050565b5f5f83601f840112610f3057610f2f610c42565b5b8235905067ffffffffffffffff811115610f4d57610f4c610c46565b5b602083019150836001820283011115610f6957610f68610c4a565b5b9250929050565b5f5f5f60408486031215610f8757610f86610c3a565b5b5f610f9486828701610f07565b935050602084013567ffffffffffffffff811115610fb557610fb4610c3e565b5b610fc186828701610f1b565b92509250509250925092565b5f82825260208201905092915050565b5f610fe782610d9f565b610ff18185610fcd565b9350611001818560208601610db9565b61100a81610dc7565b840191505092915050565b5f6020820190508181035f83015261102d8184610fdd565b905092915050565b61103e81610ee0565b82525050565b5f6020820190506110575f830184611035565b92915050565b5f6020828403121561107257611071610c3a565b5b5f61107f84828501610f07565b91505092915050565b5f819050919050565b61109a81611088565b81146110a4575f5ffd5b50565b5f813590506110b581611091565b92915050565b5f5f5f5f606085870312156110d3576110d2610c3a565b5b5f6110e087828801610f07565b945050602085013567ffffffffffffffff81111561110157611100610c3e565b5b61110d87828801610f1b565b93509350506040611120878288016110a7565b91505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126111ae576111ad611186565b5b80840192508235915067ffffffffffffffff8211156111d0576111cf61118a565b5b6020830192506001820236038313156111ec576111eb61118e565b5b509250929050565b5f81905092915050565b828183375f83830152505050565b5f61121783856111f4565b93506112248385846111fe565b82840190509392505050565b5f61123c82848661120c565b91508190509392505050565b5f6112538385610fcd565b93506112608385846111fe565b61126983610dc7565b840190509392505050565b5f6040820190508181035f83015261128d818587611248565b905081810360208301526112a18184610fdd565b905094935050505056"); /// Build a genesis alloc entry for `AdminProxy`. -pub(crate) fn build(config: &AdminProxyConfig) -> GenesisContract { +pub fn build(config: &AdminProxyConfig) -> GenesisContract { let mut storage = BTreeMap::new(); // Slot 0: owner (address left-padded to 32 bytes) diff --git a/bin/ev-deployer/src/contracts/immutables.rs b/bin/ev-deployer/src/contracts/immutables.rs index 0934104..9eab22e 100644 --- a/bin/ev-deployer/src/contracts/immutables.rs +++ b/bin/ev-deployer/src/contracts/immutables.rs @@ -10,7 +10,7 @@ use alloy_primitives::{B256, U256}; /// A single immutable reference inside a bytecode blob. #[derive(Debug, Clone, Copy)] -pub(crate) struct ImmutableRef { +pub struct ImmutableRef { /// Byte offset into the **runtime** bytecode. pub start: usize, /// Number of bytes (always 32 for EVM words). @@ -22,7 +22,7 @@ pub(crate) struct ImmutableRef { /// # Panics /// /// Panics if any reference extends past the end of `bytecode`. -pub(crate) fn patch_bytes(bytecode: &mut [u8], refs: &[ImmutableRef], value: &[u8; 32]) { +pub fn patch_bytes(bytecode: &mut [u8], refs: &[ImmutableRef], value: &[u8; 32]) { for r in refs { assert!( r.start + r.length <= bytecode.len(), @@ -36,7 +36,7 @@ pub(crate) fn patch_bytes(bytecode: &mut [u8], refs: &[ImmutableRef], value: &[u } /// Convenience: patch with an ABI-encoded `uint256`. -pub(crate) fn patch_u256(bytecode: &mut [u8], refs: &[ImmutableRef], val: U256) { +pub fn patch_u256(bytecode: &mut [u8], refs: &[ImmutableRef], val: U256) { let word = B256::from(val); patch_bytes(bytecode, refs, &word.0); } diff --git a/bin/ev-deployer/src/contracts/mod.rs b/bin/ev-deployer/src/contracts/mod.rs index 9e61b58..c99c513 100644 --- a/bin/ev-deployer/src/contracts/mod.rs +++ b/bin/ev-deployer/src/contracts/mod.rs @@ -1,14 +1,15 @@ //! Contract bytecode and storage encoding. -pub(crate) mod admin_proxy; -pub(crate) mod immutables; -pub(crate) mod permit2; +pub mod admin_proxy; +pub mod immutables; +pub mod permit2; use alloy_primitives::{Address, Bytes, B256}; use std::collections::BTreeMap; /// A contract ready to be placed in genesis alloc. -pub(crate) struct GenesisContract { +#[derive(Debug)] +pub struct GenesisContract { /// The address to deploy at. pub address: Address, /// Runtime bytecode. diff --git a/bin/ev-deployer/src/contracts/permit2.rs b/bin/ev-deployer/src/contracts/permit2.rs index ee56f85..00a1380 100644 --- a/bin/ev-deployer/src/contracts/permit2.rs +++ b/bin/ev-deployer/src/contracts/permit2.rs @@ -68,7 +68,7 @@ const HASHED_NAME: B256 = B256::new(hex!( )); /// Build a genesis alloc entry for `Permit2`. -pub(crate) fn build(config: &Permit2Config, chain_id: u64) -> GenesisContract { +pub fn build(config: &Permit2Config, chain_id: u64) -> GenesisContract { let mut bytecode = PERMIT2_BYTECODE.to_vec(); // Patch _CACHED_CHAIN_ID diff --git a/bin/ev-deployer/src/genesis.rs b/bin/ev-deployer/src/genesis.rs index e270b69..fb3bfb2 100644 --- a/bin/ev-deployer/src/genesis.rs +++ b/bin/ev-deployer/src/genesis.rs @@ -9,7 +9,7 @@ use serde_json::{Map, Value}; use std::path::Path; /// Build the alloc JSON from config. -pub(crate) fn build_alloc(config: &DeployConfig) -> Value { +pub fn build_alloc(config: &DeployConfig) -> Value { let mut alloc = Map::new(); if let Some(ref ap_config) = config.contracts.admin_proxy { @@ -26,14 +26,15 @@ pub(crate) fn build_alloc(config: &DeployConfig) -> Value { } /// Build alloc and merge into an existing genesis JSON file. -pub(crate) fn merge_into( - config: &DeployConfig, - genesis_path: &Path, - force: bool, -) -> eyre::Result { +pub fn merge_into(config: &DeployConfig, genesis_path: &Path, force: bool) -> eyre::Result { let content = std::fs::read_to_string(genesis_path)?; let mut genesis: Value = serde_json::from_str(&content)?; + merge_alloc(config, &mut genesis, force)?; + Ok(genesis) +} +/// Merge deployer contracts into a genesis JSON value in memory. +pub fn merge_alloc(config: &DeployConfig, genesis: &mut Value, force: bool) -> eyre::Result<()> { let alloc = build_alloc(config); let genesis_alloc = genesis @@ -57,7 +58,7 @@ pub(crate) fn merge_into( genesis_alloc.insert(canonical, entry.clone()); } - Ok(genesis) + Ok(()) } fn normalize_addr(addr: &str) -> String { diff --git a/bin/ev-deployer/src/lib.rs b/bin/ev-deployer/src/lib.rs new file mode 100644 index 0000000..08bca34 --- /dev/null +++ b/bin/ev-deployer/src/lib.rs @@ -0,0 +1,9 @@ +//! EV Deployer — genesis alloc generator for ev-reth contracts. +//! +//! This crate provides both a CLI tool and a library for generating genesis +//! alloc entries from declarative TOML configurations. + +pub mod config; +pub mod contracts; +pub mod genesis; +pub mod output; diff --git a/bin/ev-deployer/src/main.rs b/bin/ev-deployer/src/main.rs index 5d87ae9..daeea7d 100644 --- a/bin/ev-deployer/src/main.rs +++ b/bin/ev-deployer/src/main.rs @@ -1,11 +1,7 @@ //! EV Deployer — genesis alloc generator for ev-reth contracts. -mod config; -mod contracts; -mod genesis; -mod output; - use clap::{Parser, Subcommand}; +use ev_deployer::{config, genesis, output}; use std::path::PathBuf; /// EV Deployer: generate genesis alloc entries for ev-reth contracts. diff --git a/bin/ev-deployer/src/output.rs b/bin/ev-deployer/src/output.rs index f683377..83da3f7 100644 --- a/bin/ev-deployer/src/output.rs +++ b/bin/ev-deployer/src/output.rs @@ -4,7 +4,7 @@ use crate::config::DeployConfig; use serde_json::{Map, Value}; /// Build an address manifest JSON from config. -pub(crate) fn build_manifest(config: &DeployConfig) -> Value { +pub fn build_manifest(config: &DeployConfig) -> Value { let mut manifest = Map::new(); if let Some(ref ap) = config.contracts.admin_proxy { diff --git a/bin/ev-dev/Cargo.toml b/bin/ev-dev/Cargo.toml index 99a72d1..5a10743 100644 --- a/bin/ev-dev/Cargo.toml +++ b/bin/ev-dev/Cargo.toml @@ -15,6 +15,7 @@ path = "src/main.rs" [dependencies] # Core evolve crates ev-node = { path = "../../crates/node" } +ev-deployer = { path = "../ev-deployer" } evolve-ev-reth = { path = "../../crates/evolve" } # Reth CLI and core dependencies diff --git a/bin/ev-dev/README.md b/bin/ev-dev/README.md index 39a615f..731a6e2 100644 --- a/bin/ev-dev/README.md +++ b/bin/ev-dev/README.md @@ -28,6 +28,7 @@ ev-dev [OPTIONS] | `--block-time` | `1` | Block time in seconds (`0` = mine on transaction) | | `--silent` | `false` | Suppress the startup banner | | `--accounts` | `10` | Number of accounts to display (1-20) | +| `--deploy-config` | — | Path to an ev-deployer TOML config to deploy contracts at genesis | ### Examples @@ -40,8 +41,38 @@ ev-dev --host 0.0.0.0 # Custom port, faster blocks ev-dev --port 9545 --block-time 2 + +# Start with genesis contracts deployed +ev-dev --deploy-config bin/ev-deployer/examples/devnet.toml ``` +## Genesis Contract Deployment + +You can deploy contracts into the genesis state by passing a `--deploy-config` flag pointing to an [ev-deployer](../ev-deployer/README.md) TOML config file. + +```bash +ev-dev --deploy-config path/to/deploy.toml +``` + +When a deploy config is provided, ev-dev will: + +1. Load and validate the config +2. Override the config's `chain_id` to match the devnet genesis (a warning is printed if they differ) +3. Merge the contract alloc entries into the genesis state before starting the node +4. Print the deployed contract addresses in the startup banner + +The startup banner will show an extra section: + +``` +Genesis Contracts (from path/to/deploy.toml) +================== + admin_proxy "0x000000000000000000000000000000000000Ad00" + fee_vault "0x000000000000000000000000000000000000FE00" + ... +``` + +See the [ev-deployer README](../ev-deployer/README.md) for full config reference and available contracts. + ## Chain Details | Property | Value | @@ -204,9 +235,10 @@ ev-dev includes all Evolve customizations out of the box: ev-dev is a thin wrapper around the full `ev-reth` node. On startup it: -1. Writes the embedded devnet genesis to a temp file -2. Creates a temporary data directory (clean state every run) -3. Launches `ev-reth` in `--dev` mode with networking disabled -4. Exposes HTTP and WebSocket RPC on the configured host/port +1. If `--deploy-config` is provided, loads the config and merges contract alloc entries into the genesis +2. Writes the (possibly extended) devnet genesis to a temp file +3. Creates a temporary data directory (clean state every run) +4. Launches `ev-reth` in `--dev` mode with networking disabled +5. Exposes HTTP and WebSocket RPC on the configured host/port Each run starts from a fresh genesis — there is no persistent state between restarts. diff --git a/bin/ev-dev/src/main.rs b/bin/ev-dev/src/main.rs index 7ed4e65..6eeef39 100644 --- a/bin/ev-dev/src/main.rs +++ b/bin/ev-dev/src/main.rs @@ -7,12 +7,13 @@ use alloy_signer_local::{coins_bip39::English, MnemonicBuilder}; use clap::Parser; +use ev_deployer::{config::DeployConfig, genesis::merge_alloc, output::build_manifest}; use evolve_ev_reth::{ config::EvolveConfig, rpc::txpool::{EvolveTxpoolApiImpl, EvolveTxpoolApiServer}, }; use reth_ethereum_cli::Cli; -use std::io::Write; +use std::{io::Write, path::PathBuf}; use tracing::info; use ev_node::{EvolveArgs, EvolveChainSpecParser, EvolveNode}; @@ -55,6 +56,10 @@ struct EvDevArgs { /// Number of accounts to display (1..=20) #[arg(long, default_value_t = 10, value_parser = parse_accounts)] accounts: usize, + + /// Path to an ev-deployer TOML config to deploy contracts at genesis. + #[arg(long, value_name = "PATH")] + deploy_config: Option, } fn derive_keys(count: usize) -> Vec<(String, String)> { @@ -84,7 +89,7 @@ fn chain_id_from_genesis() -> u64 { .expect("genesis must have config.chainId") } -fn print_banner(args: &EvDevArgs) { +fn print_banner(args: &EvDevArgs, deploy_cfg: Option<&DeployConfig>) { let accounts = derive_keys(args.accounts); println!(); @@ -124,6 +129,20 @@ fn print_banner(args: &EvDevArgs) { println!("Mnemonic: {HARDHAT_MNEMONIC}"); println!("Derivation path: m/44'/60'/0'/0/{{index}}"); println!(); + + if let Some(cfg) = deploy_cfg { + let config_path = args.deploy_config.as_ref().unwrap(); + println!("Genesis Contracts (from {})", config_path.display()); + println!("=================="); + let manifest = build_manifest(cfg); + if let Some(obj) = manifest.as_object() { + for (name, addr) in obj { + println!(" {name:20} {addr}"); + } + } + println!(); + } + println!("WARNING: These accounts and keys are publicly known."); println!("Any funds sent to them on mainnet WILL BE LOST."); println!(); @@ -138,15 +157,39 @@ fn main() { let dev_args = EvDevArgs::parse(); + let deploy_cfg = dev_args.deploy_config.as_ref().map(|config_path| { + let mut cfg = DeployConfig::load(config_path) + .unwrap_or_else(|e| panic!("failed to load deploy config: {e}")); + + let genesis_chain_id = chain_id_from_genesis(); + if cfg.chain.chain_id != genesis_chain_id { + eprintln!( + "WARNING: deploy config chain_id ({}) differs from devnet genesis ({}), overriding to {}", + cfg.chain.chain_id, genesis_chain_id, genesis_chain_id + ); + cfg.chain.chain_id = genesis_chain_id; + } + cfg + }); + if !dev_args.silent { - print_banner(&dev_args); + print_banner(&dev_args, deploy_cfg.as_ref()); } + let genesis_json = if let Some(ref cfg) = deploy_cfg { + let mut genesis: serde_json::Value = + serde_json::from_str(DEVNET_GENESIS).expect("valid genesis JSON"); + merge_alloc(cfg, &mut genesis, true).expect("failed to merge deploy config into genesis"); + serde_json::to_string(&genesis).expect("failed to serialize merged genesis") + } else { + DEVNET_GENESIS.to_string() + }; + // Write genesis to a temp file that lives for the process duration let mut genesis_file = tempfile::NamedTempFile::new().expect("failed to create temp genesis file"); genesis_file - .write_all(DEVNET_GENESIS.as_bytes()) + .write_all(genesis_json.as_bytes()) .expect("failed to write genesis"); let genesis_path = genesis_file .path() diff --git a/justfile b/justfile index 757a5b9..941833a 100644 --- a/justfile +++ b/justfile @@ -38,6 +38,14 @@ build-all: build-deployer: {{cargo}} build --release --bin ev-deployer +# Install ev-dev to ~/.cargo/bin +install-ev-dev: + {{cargo}} install --path bin/ev-dev + +# Install ev-deployer to ~/.cargo/bin +install-ev-deployer: + {{cargo}} install --path bin/ev-deployer + # Testing ────────────────────────────────────────────── # Run all tests