From 6070a3b5c850d4898abf2dd4ff25393366633343 Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 16:46:30 +0200 Subject: [PATCH 01/18] refactor(ev-deployer): make address optional in contract configs Prepares for the deploy subcommand where addresses are determined by CREATE2, not by user config. Genesis mode validates addresses are present. --- bin/ev-deployer/src/config.rs | 75 +++++++++++++++----- bin/ev-deployer/src/contracts/admin_proxy.rs | 7 +- bin/ev-deployer/src/contracts/permit2.rs | 40 ++++++----- bin/ev-deployer/src/genesis.rs | 2 +- bin/ev-deployer/src/main.rs | 9 +-- bin/ev-deployer/src/output.rs | 20 +++--- 6 files changed, 103 insertions(+), 50 deletions(-) diff --git a/bin/ev-deployer/src/config.rs b/bin/ev-deployer/src/config.rs index f289611..ba02a62 100644 --- a/bin/ev-deployer/src/config.rs +++ b/bin/ev-deployer/src/config.rs @@ -1,11 +1,11 @@ //! TOML config types, parsing, and validation. use alloy_primitives::Address; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use std::{collections::HashSet, path::Path}; /// Top-level deploy configuration. -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub(crate) struct DeployConfig { /// Chain configuration. pub chain: ChainConfig, @@ -15,14 +15,14 @@ pub(crate) struct DeployConfig { } /// Chain-level settings. -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub(crate) struct ChainConfig { /// The chain ID. pub chain_id: u64, } /// All contract configurations. -#[derive(Debug, Deserialize, Default)] +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)] pub(crate) struct ContractsConfig { /// `AdminProxy` contract config (optional). pub admin_proxy: Option, @@ -35,29 +35,33 @@ impl ContractsConfig { fn all_addresses(&self) -> Vec
{ let mut addrs = Vec::new(); if let Some(ref ap) = self.admin_proxy { - addrs.push(ap.address); + if let Some(addr) = ap.address { + addrs.push(addr); + } } if let Some(ref p2) = self.permit2 { - addrs.push(p2.address); + if let Some(addr) = p2.address { + addrs.push(addr); + } } addrs } } /// `AdminProxy` configuration. -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub(crate) struct AdminProxyConfig { - /// Address to deploy at. - pub address: Address, + /// Address to deploy at (required for genesis, ignored for deploy). + pub address: Option
, /// Owner address. pub owner: Address, } /// `Permit2` configuration (Uniswap token approval manager). -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub(crate) struct Permit2Config { - /// Address to deploy at. - pub address: Address, + /// Address to deploy at (required for genesis, ignored for deploy). + pub address: Option
, } impl DeployConfig { @@ -70,7 +74,7 @@ impl DeployConfig { } /// Validate config values. - fn validate(&self) -> eyre::Result<()> { + pub(crate) fn validate(&self) -> eyre::Result<()> { if let Some(ref ap) = self.contracts.admin_proxy { eyre::ensure!( !ap.owner.is_zero(), @@ -79,10 +83,12 @@ impl DeployConfig { } if let Some(ref p2) = self.contracts.permit2 { - eyre::ensure!( - !p2.address.is_zero(), - "permit2.address must not be the zero address" - ); + if let Some(addr) = p2.address { + eyre::ensure!( + !addr.is_zero(), + "permit2.address must not be the zero address" + ); + } } // Detect duplicate deploy addresses across all contracts. @@ -93,6 +99,23 @@ impl DeployConfig { Ok(()) } + + /// Additional validation for genesis mode: all addresses must be specified. + pub(crate) fn validate_for_genesis(&self) -> eyre::Result<()> { + if let Some(ref ap) = self.contracts.admin_proxy { + eyre::ensure!( + ap.address.is_some(), + "admin_proxy.address is required for genesis mode" + ); + } + if let Some(ref p2) = self.contracts.permit2 { + eyre::ensure!( + p2.address.is_some(), + "permit2.address is required for genesis mode" + ); + } + Ok(()) + } } #[cfg(test)] @@ -205,6 +228,24 @@ address = "0x000000000022D473030F116dDEE9F6B43aC78BA3" assert!(config.contracts.permit2.is_some()); } + #[test] + fn reject_missing_address_for_genesis() { + use alloy_primitives::address; + + let config = DeployConfig { + chain: ChainConfig { chain_id: 1 }, + contracts: ContractsConfig { + admin_proxy: Some(AdminProxyConfig { + address: None, + owner: address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), + }), + permit2: None, + }, + }; + config.validate().unwrap(); // base validation passes + assert!(config.validate_for_genesis().is_err()); + } + #[test] fn admin_proxy_only() { let toml = r#" diff --git a/bin/ev-deployer/src/contracts/admin_proxy.rs b/bin/ev-deployer/src/contracts/admin_proxy.rs index ed187b1..33c4f54 100644 --- a/bin/ev-deployer/src/contracts/admin_proxy.rs +++ b/bin/ev-deployer/src/contracts/admin_proxy.rs @@ -6,10 +6,11 @@ use std::collections::BTreeMap; /// `AdminProxy` runtime bytecode compiled with solc 0.8.33 (`cbor_metadata=false`). /// Regenerate with: `cd contracts && forge inspect AdminProxy deployedBytecode` -const ADMIN_PROXY_BYTECODE: &[u8] = &hex!("60806040526004361061007e575f3560e01c80638da5cb5b1161004d5780638da5cb5b1461012d578063e30c397814610157578063f2fde38b14610181578063fa4bb79d146101a957610085565b806318dfb3c7146100895780631cff79cd146100c557806379ba5097146101015780638b5298541461011757610085565b3661008557005b5f5ffd5b348015610094575f5ffd5b506100af60048036038101906100aa9190610cf8565b6101e5565b6040516100bc9190610ea1565b60405180910390f35b3480156100d0575f5ffd5b506100eb60048036038101906100e69190610f70565b6104d9565b6040516100f89190611015565b60405180910390f35b34801561010c575f5ffd5b5061011561066c565b005b348015610122575f5ffd5b5061012b6107ed565b005b348015610138575f5ffd5b506101416108b4565b60405161014e9190611044565b60405180910390f35b348015610162575f5ffd5b5061016b6108d8565b6040516101789190611044565b60405180910390f35b34801561018c575f5ffd5b506101a760048036038101906101a2919061105d565b6108fd565b005b3480156101b4575f5ffd5b506101cf60048036038101906101ca91906110bb565b610aa4565b6040516101dc9190611015565b60405180910390f35b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026c576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282905085859050146102ab576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484905067ffffffffffffffff8111156102c8576102c761112c565b5b6040519080825280602002602001820160405280156102fb57816020015b60608152602001906001900390816102e65790505b5090505f5f90505b858590508110156104d0575f5f87878481811061032357610322611159565b5b9050602002016020810190610338919061105d565b73ffffffffffffffffffffffffffffffffffffffff1686868581811061036157610360611159565b5b90506020028101906103739190611192565b604051610381929190611230565b5f604051808303815f865af19150503d805f81146103ba576040519150601f19603f3d011682016040523d82523d5f602084013e6103bf565b606091505b50915091508161040657806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016103fd9190611015565b60405180910390fd5b87878481811061041957610418611159565b5b905060200201602081019061042e919061105d565b73ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb587878681811061047857610477611159565b5b905060200281019061048a9190611192565b8460405161049a93929190611274565b60405180910390a2808484815181106104b6576104b5611159565b5b602002602001018190525050508080600101915050610303565b50949350505050565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610560576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8573ffffffffffffffffffffffffffffffffffffffff168585604051610589929190611230565b5f604051808303815f865af19150503d805f81146105c2576040519150601f19603f3d011682016040523d82523d5f602084013e6105c7565b606091505b50915091508161060e57806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016106059190611015565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb586868460405161065893929190611274565b60405180910390a280925050509392505050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106f2576040517f1853971c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3335f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610872576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610982576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036109e7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b2b576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff16848787604051610b55929190611230565b5f6040518083038185875af1925050503d805f8114610b8f576040519150601f19603f3d011682016040523d82523d5f602084013e610b94565b606091505b509150915081610bdb57806040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152600401610bd29190611015565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb5878784604051610c2593929190611274565b60405180910390a28092505050949350505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112610c6357610c62610c42565b5b8235905067ffffffffffffffff811115610c8057610c7f610c46565b5b602083019150836020820283011115610c9c57610c9b610c4a565b5b9250929050565b5f5f83601f840112610cb857610cb7610c42565b5b8235905067ffffffffffffffff811115610cd557610cd4610c46565b5b602083019150836020820283011115610cf157610cf0610c4a565b5b9250929050565b5f5f5f5f60408587031215610d1057610d0f610c3a565b5b5f85013567ffffffffffffffff811115610d2d57610d2c610c3e565b5b610d3987828801610c4e565b9450945050602085013567ffffffffffffffff811115610d5c57610d5b610c3e565b5b610d6887828801610ca3565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610de182610d9f565b610deb8185610da9565b9350610dfb818560208601610db9565b610e0481610dc7565b840191505092915050565b5f610e1a8383610dd7565b905092915050565b5f602082019050919050565b5f610e3882610d76565b610e428185610d80565b935083602082028501610e5485610d90565b805f5b85811015610e8f5784840389528151610e708582610e0f565b9450610e7b83610e22565b925060208a01995050600181019050610e57565b50829750879550505050505092915050565b5f6020820190508181035f830152610eb98184610e2e565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610eea82610ec1565b9050919050565b610efa81610ee0565b8114610f04575f5ffd5b50565b5f81359050610f1581610ef1565b92915050565b5f5f83601f840112610f3057610f2f610c42565b5b8235905067ffffffffffffffff811115610f4d57610f4c610c46565b5b602083019150836001820283011115610f6957610f68610c4a565b5b9250929050565b5f5f5f60408486031215610f8757610f86610c3a565b5b5f610f9486828701610f07565b935050602084013567ffffffffffffffff811115610fb557610fb4610c3e565b5b610fc186828701610f1b565b92509250509250925092565b5f82825260208201905092915050565b5f610fe782610d9f565b610ff18185610fcd565b9350611001818560208601610db9565b61100a81610dc7565b840191505092915050565b5f6020820190508181035f83015261102d8184610fdd565b905092915050565b61103e81610ee0565b82525050565b5f6020820190506110575f830184611035565b92915050565b5f6020828403121561107257611071610c3a565b5b5f61107f84828501610f07565b91505092915050565b5f819050919050565b61109a81611088565b81146110a4575f5ffd5b50565b5f813590506110b581611091565b92915050565b5f5f5f5f606085870312156110d3576110d2610c3a565b5b5f6110e087828801610f07565b945050602085013567ffffffffffffffff81111561110157611100610c3e565b5b61110d87828801610f1b565b93509350506040611120878288016110a7565b91505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126111ae576111ad611186565b5b80840192508235915067ffffffffffffffff8211156111d0576111cf61118a565b5b6020830192506001820236038313156111ec576111eb61118e565b5b509250929050565b5f81905092915050565b828183375f83830152505050565b5f61121783856111f4565b93506112248385846111fe565b82840190509392505050565b5f61123c82848661120c565b91508190509392505050565b5f6112538385610fcd565b93506112608385846111fe565b61126983610dc7565b840190509392505050565b5f6040820190508181035f83015261128d818587611248565b905081810360208301526112a18184610fdd565b905094935050505056"); +pub(crate) const ADMIN_PROXY_BYTECODE: &[u8] = &hex!("60806040526004361061007e575f3560e01c80638da5cb5b1161004d5780638da5cb5b1461012d578063e30c397814610157578063f2fde38b14610181578063fa4bb79d146101a957610085565b806318dfb3c7146100895780631cff79cd146100c557806379ba5097146101015780638b5298541461011757610085565b3661008557005b5f5ffd5b348015610094575f5ffd5b506100af60048036038101906100aa9190610cf8565b6101e5565b6040516100bc9190610ea1565b60405180910390f35b3480156100d0575f5ffd5b506100eb60048036038101906100e69190610f70565b6104d9565b6040516100f89190611015565b60405180910390f35b34801561010c575f5ffd5b5061011561066c565b005b348015610122575f5ffd5b5061012b6107ed565b005b348015610138575f5ffd5b506101416108b4565b60405161014e9190611044565b60405180910390f35b348015610162575f5ffd5b5061016b6108d8565b6040516101789190611044565b60405180910390f35b34801561018c575f5ffd5b506101a760048036038101906101a2919061105d565b6108fd565b005b3480156101b4575f5ffd5b506101cf60048036038101906101ca91906110bb565b610aa4565b6040516101dc9190611015565b60405180910390f35b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026c576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282905085859050146102ab576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484905067ffffffffffffffff8111156102c8576102c761112c565b5b6040519080825280602002602001820160405280156102fb57816020015b60608152602001906001900390816102e65790505b5090505f5f90505b858590508110156104d0575f5f87878481811061032357610322611159565b5b9050602002016020810190610338919061105d565b73ffffffffffffffffffffffffffffffffffffffff1686868581811061036157610360611159565b5b90506020028101906103739190611192565b604051610381929190611230565b5f604051808303815f865af19150503d805f81146103ba576040519150601f19603f3d011682016040523d82523d5f602084013e6103bf565b606091505b50915091508161040657806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016103fd9190611015565b60405180910390fd5b87878481811061041957610418611159565b5b905060200201602081019061042e919061105d565b73ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb587878681811061047857610477611159565b5b905060200281019061048a9190611192565b8460405161049a93929190611274565b60405180910390a2808484815181106104b6576104b5611159565b5b602002602001018190525050508080600101915050610303565b50949350505050565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610560576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8573ffffffffffffffffffffffffffffffffffffffff168585604051610589929190611230565b5f604051808303815f865af19150503d805f81146105c2576040519150601f19603f3d011682016040523d82523d5f602084013e6105c7565b606091505b50915091508161060e57806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016106059190611015565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb586868460405161065893929190611274565b60405180910390a280925050509392505050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106f2576040517f1853971c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3335f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610872576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610982576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036109e7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b2b576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff16848787604051610b55929190611230565b5f6040518083038185875af1925050503d805f8114610b8f576040519150601f19603f3d011682016040523d82523d5f602084013e610b94565b606091505b509150915081610bdb57806040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152600401610bd29190611015565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb5878784604051610c2593929190611274565b60405180910390a28092505050949350505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112610c6357610c62610c42565b5b8235905067ffffffffffffffff811115610c8057610c7f610c46565b5b602083019150836020820283011115610c9c57610c9b610c4a565b5b9250929050565b5f5f83601f840112610cb857610cb7610c42565b5b8235905067ffffffffffffffff811115610cd557610cd4610c46565b5b602083019150836020820283011115610cf157610cf0610c4a565b5b9250929050565b5f5f5f5f60408587031215610d1057610d0f610c3a565b5b5f85013567ffffffffffffffff811115610d2d57610d2c610c3e565b5b610d3987828801610c4e565b9450945050602085013567ffffffffffffffff811115610d5c57610d5b610c3e565b5b610d6887828801610ca3565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610de182610d9f565b610deb8185610da9565b9350610dfb818560208601610db9565b610e0481610dc7565b840191505092915050565b5f610e1a8383610dd7565b905092915050565b5f602082019050919050565b5f610e3882610d76565b610e428185610d80565b935083602082028501610e5485610d90565b805f5b85811015610e8f5784840389528151610e708582610e0f565b9450610e7b83610e22565b925060208a01995050600181019050610e57565b50829750879550505050505092915050565b5f6020820190508181035f830152610eb98184610e2e565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610eea82610ec1565b9050919050565b610efa81610ee0565b8114610f04575f5ffd5b50565b5f81359050610f1581610ef1565b92915050565b5f5f83601f840112610f3057610f2f610c42565b5b8235905067ffffffffffffffff811115610f4d57610f4c610c46565b5b602083019150836001820283011115610f6957610f68610c4a565b5b9250929050565b5f5f5f60408486031215610f8757610f86610c3a565b5b5f610f9486828701610f07565b935050602084013567ffffffffffffffff811115610fb557610fb4610c3e565b5b610fc186828701610f1b565b92509250509250925092565b5f82825260208201905092915050565b5f610fe782610d9f565b610ff18185610fcd565b9350611001818560208601610db9565b61100a81610dc7565b840191505092915050565b5f6020820190508181035f83015261102d8184610fdd565b905092915050565b61103e81610ee0565b82525050565b5f6020820190506110575f830184611035565b92915050565b5f6020828403121561107257611071610c3a565b5b5f61107f84828501610f07565b91505092915050565b5f819050919050565b61109a81611088565b81146110a4575f5ffd5b50565b5f813590506110b581611091565b92915050565b5f5f5f5f606085870312156110d3576110d2610c3a565b5b5f6110e087828801610f07565b945050602085013567ffffffffffffffff81111561110157611100610c3e565b5b61110d87828801610f1b565b93509350506040611120878288016110a7565b91505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126111ae576111ad611186565b5b80840192508235915067ffffffffffffffff8211156111d0576111cf61118a565b5b6020830192506001820236038313156111ec576111eb61118e565b5b509250929050565b5f81905092915050565b828183375f83830152505050565b5f61121783856111f4565b93506112248385846111fe565b82840190509392505050565b5f61123c82848661120c565b91508190509392505050565b5f6112538385610fcd565b93506112608385846111fe565b61126983610dc7565b840190509392505050565b5f6040820190508181035f83015261128d818587611248565b905081810360208301526112a18184610fdd565b905094935050505056"); /// Build a genesis alloc entry for `AdminProxy`. pub(crate) fn build(config: &AdminProxyConfig) -> GenesisContract { + let address = config.address.expect("address required for genesis"); let mut storage = BTreeMap::new(); // Slot 0: owner (address left-padded to 32 bytes) @@ -17,7 +18,7 @@ pub(crate) fn build(config: &AdminProxyConfig) -> GenesisContract { storage.insert(B256::ZERO, owner_value); GenesisContract { - address: config.address, + address, code: Bytes::from_static(ADMIN_PROXY_BYTECODE), storage, } @@ -32,7 +33,7 @@ mod tests { #[test] fn golden_admin_proxy_storage() { let config = AdminProxyConfig { - address: address!("000000000000000000000000000000000000Ad00"), + address: Some(address!("000000000000000000000000000000000000Ad00")), owner: address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), }; let contract = build(&config); diff --git a/bin/ev-deployer/src/contracts/permit2.rs b/bin/ev-deployer/src/contracts/permit2.rs index ee56f85..ef438b1 100644 --- a/bin/ev-deployer/src/contracts/permit2.rs +++ b/bin/ev-deployer/src/contracts/permit2.rs @@ -28,7 +28,7 @@ use crate::{ GenesisContract, }, }; -use alloy_primitives::{hex, keccak256, Bytes, B256, U256}; +use alloy_primitives::{hex, keccak256, Address, Bytes, B256, U256}; use std::collections::BTreeMap; /// `Permit2` runtime bytecode compiled from Uniswap/permit2 (commit cc56ad0) @@ -41,47 +41,45 @@ use std::collections::BTreeMap; /// ```sh /// cd contracts/lib/permit2 && forge inspect Permit2 deployedBytecode /// ``` -const PERMIT2_BYTECODE: &[u8] = &hex!("6040608081526004908136101561001557600080fd5b600090813560e01c80630d58b1db1461126c578063137c29fe146110755780632a2d80d114610db75780632b67b57014610bde57806330f28b7a14610ade5780633644e51514610a9d57806336c7851614610a285780633ff9dcb1146109a85780634fe02b441461093f57806365d9723c146107ac57806387517c451461067a578063927da105146105c3578063cc53287f146104a3578063edd9444b1461033a5763fe8ec1a7146100c657600080fd5b346103365760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365767ffffffffffffffff833581811161033257610114903690860161164b565b60243582811161032e5761012b903690870161161a565b6101336114e6565b9160843585811161032a5761014b9036908a016115c1565b98909560a43590811161032657610164913691016115c1565b969095815190610173826113ff565b606b82527f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208301527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c61646472838301527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608301527f3620646561646c696e652c000000000000000000000000000000000000000000608083015282519a8b9181610222602085018096611f93565b918237018a8152039961025b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09b8c8101835282611437565b5190209085515161026b81611ebb565b908a5b8181106102f95750506102f6999a6102ed9183516102a081610294602082018095611f66565b03848101835282611437565b519020602089810151858b015195519182019687526040820192909252336060820152608081019190915260a081019390935260643560c08401528260e081015b03908101835282611437565b51902093611cf7565b80f35b8061031161030b610321938c5161175e565b51612054565b61031b828661175e565b52611f0a565b61026e565b8880fd5b8780fd5b8480fd5b8380fd5b5080fd5b5091346103365760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365767ffffffffffffffff9080358281116103325761038b903690830161164b565b60243583811161032e576103a2903690840161161a565b9390926103ad6114e6565b9160643590811161049f576103c4913691016115c1565b949093835151976103d489611ebb565b98885b81811061047d5750506102f697988151610425816103f9602082018095611f66565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611437565b5190206020860151828701519083519260208401947ffcf35f5ac6a2c28868dc44c302166470266239195f02b0ee408334829333b7668652840152336060840152608083015260a082015260a081526102ed8161141b565b808b61031b8261049461030b61049a968d5161175e565b9261175e565b6103d7565b8680fd5b5082346105bf57602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103325780359067ffffffffffffffff821161032e576104f49136910161161a565b929091845b848110610504578580f35b8061051a610515600193888861196c565b61197c565b61052f84610529848a8a61196c565b0161197c565b3389528385528589209173ffffffffffffffffffffffffffffffffffffffff80911692838b528652868a20911690818a5285528589207fffffffffffffffffffffffff000000000000000000000000000000000000000081541690558551918252848201527f89b1add15eff56b3dfe299ad94e01f2b52fbcb80ae1a3baea6ae8c04cb2b98a4853392a2016104f9565b8280fd5b50346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610676816105ff6114a0565b936106086114c3565b6106106114e6565b73ffffffffffffffffffffffffffffffffffffffff968716835260016020908152848420928816845291825283832090871683528152919020549251938316845260a083901c65ffffffffffff169084015260d09190911c604083015281906060820190565b0390f35b50346103365760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576106b26114a0565b906106bb6114c3565b916106c46114e6565b65ffffffffffff926064358481169081810361032a5779ffffffffffff0000000000000000000000000000000000000000947fda9fa7c1b00402c17d0161b249b1ab8bbec047c5a52207b9c112deffd817036b94338a5260016020527fffffffffffff0000000000000000000000000000000000000000000000000000858b209873ffffffffffffffffffffffffffffffffffffffff809416998a8d5260205283878d209b169a8b8d52602052868c209486156000146107a457504216925b8454921697889360a01b16911617179055815193845260208401523392a480f35b905092610783565b5082346105bf5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf576107e56114a0565b906107ee6114c3565b9265ffffffffffff604435818116939084810361032a57338852602091600183528489209673ffffffffffffffffffffffffffffffffffffffff80911697888b528452858a20981697888a5283528489205460d01c93848711156109175761ffff9085840316116108f05750907f55eb90d810e1700b35a8e7e25395ff7f2b2259abd7415ca2284dfb1c246418f393929133895260018252838920878a528252838920888a5282528389209079ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffff000000000000000000000000000000000000000000000000000083549260d01b16911617905582519485528401523392a480f35b84517f24d35a26000000000000000000000000000000000000000000000000000000008152fd5b5084517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b503461033657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336578060209273ffffffffffffffffffffffffffffffffffffffff61098f6114a0565b1681528084528181206024358252845220549051908152f35b5082346105bf57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf577f3704902f963766a4e561bbaab6e6cdc1b1dd12f6e9e99648da8843b3f46b918d90359160243533855284602052818520848652602052818520818154179055815193845260208401523392a280f35b8234610a9a5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610a9a57610a606114a0565b610a686114c3565b610a706114e6565b6064359173ffffffffffffffffffffffffffffffffffffffff8316830361032e576102f6936117a1565b80fd5b503461033657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602090610ad7611b1e565b9051908152f35b508290346105bf576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf57610b1a3661152a565b90807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c36011261033257610b4c611478565b9160e43567ffffffffffffffff8111610bda576102f694610b6f913691016115c1565b939092610b7c8351612054565b6020840151828501519083519260208401947f939c21a48a8dbe3a9a2404a1d46691e4d39f6583d6ec6b35714604c986d801068652840152336060840152608083015260a082015260a08152610bd18161141b565b51902091611c25565b8580fd5b509134610336576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610c186114a0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc360160c08112610332576080855191610c51836113e3565b1261033257845190610c6282611398565b73ffffffffffffffffffffffffffffffffffffffff91602435838116810361049f578152604435838116810361049f57602082015265ffffffffffff606435818116810361032a5788830152608435908116810361049f576060820152815260a435938285168503610bda576020820194855260c4359087830182815260e43567ffffffffffffffff811161032657610cfe90369084016115c1565b929093804211610d88575050918591610d786102f6999a610d7e95610d238851611fbe565b90898c511690519083519260208401947ff3841cd1ff0085026a6327b620b67997ce40f282c88a8e905a7a5626e310f3d086528401526060830152608082015260808152610d70816113ff565b519020611bd9565b916120c7565b519251169161199d565b602492508a51917fcd21db4f000000000000000000000000000000000000000000000000000000008352820152fd5b5091346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc93818536011261033257610df36114a0565b9260249081359267ffffffffffffffff9788851161032a578590853603011261049f578051978589018981108282111761104a578252848301358181116103265785019036602383011215610326578382013591610e50836115ef565b90610e5d85519283611437565b838252602093878584019160071b83010191368311611046578801905b828210610fe9575050508a526044610e93868801611509565b96838c01978852013594838b0191868352604435908111610fe557610ebb90369087016115c1565b959096804211610fba575050508998995151610ed681611ebb565b908b5b818110610f9757505092889492610d7892610f6497958351610f02816103f98682018095611f66565b5190209073ffffffffffffffffffffffffffffffffffffffff9a8b8b51169151928551948501957faf1b0d30d2cab0380e68f0689007e3254993c596f2fdd0aaa7f4d04f794408638752850152830152608082015260808152610d70816113ff565b51169082515192845b848110610f78578580f35b80610f918585610f8b600195875161175e565b5161199d565b01610f6d565b80610311610fac8e9f9e93610fb2945161175e565b51611fbe565b9b9a9b610ed9565b8551917fcd21db4f000000000000000000000000000000000000000000000000000000008352820152fd5b8a80fd5b6080823603126110465785608091885161100281611398565b61100b85611509565b8152611018838601611509565b838201526110278a8601611607565b8a8201528d611037818701611607565b90820152815201910190610e7a565b8c80fd5b84896041867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5082346105bf576101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf576110b03661152a565b91807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c360112610332576110e2611478565b67ffffffffffffffff93906101043585811161049f5761110590369086016115c1565b90936101243596871161032a57611125610bd1966102f6983691016115c1565b969095825190611134826113ff565b606482527f5065726d69745769746e6573735472616e7366657246726f6d28546f6b656e5060208301527f65726d697373696f6e73207065726d69747465642c6164647265737320737065848301527f6e6465722c75696e74323536206e6f6e63652c75696e7432353620646561646c60608301527f696e652c0000000000000000000000000000000000000000000000000000000060808301528351948591816111e3602085018096611f93565b918237018b8152039361121c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868101835282611437565b5190209261122a8651612054565b6020878101518589015195519182019687526040820192909252336060820152608081019190915260a081019390935260e43560c08401528260e081016102e1565b5082346105bf576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033257813567ffffffffffffffff92838211610bda5736602383011215610bda5781013592831161032e576024906007368386831b8401011161049f57865b8581106112e5578780f35b80821b83019060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc83360301126103265761139288876001946060835161132c81611398565b611368608461133c8d8601611509565b9485845261134c60448201611509565b809785015261135d60648201611509565b809885015201611509565b918291015273ffffffffffffffffffffffffffffffffffffffff80808093169516931691166117a1565b016112da565b6080810190811067ffffffffffffffff8211176113b457604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff8211176113b457604052565b60a0810190811067ffffffffffffffff8211176113b457604052565b60c0810190811067ffffffffffffffff8211176113b457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176113b457604052565b60c4359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b600080fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc01906080821261149b576040805190611563826113e3565b8082941261149b57805181810181811067ffffffffffffffff8211176113b457825260043573ffffffffffffffffffffffffffffffffffffffff8116810361149b578152602435602082015282526044356020830152606435910152565b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020838186019501011161149b57565b67ffffffffffffffff81116113b45760051b60200190565b359065ffffffffffff8216820361149b57565b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020808501948460061b01011161149b57565b91909160608184031261149b576040805191611666836113e3565b8294813567ffffffffffffffff9081811161149b57830182601f8201121561149b578035611693816115ef565b926116a087519485611437565b818452602094858086019360061b8501019381851161149b579086899897969594939201925b8484106116e3575050505050855280820135908501520135910152565b90919293949596978483031261149b578851908982019082821085831117611730578a928992845261171487611509565b81528287013583820152815201930191908897969594936116c6565b602460007f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b80518210156117725760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b92919273ffffffffffffffffffffffffffffffffffffffff604060008284168152600160205282828220961695868252602052818120338252602052209485549565ffffffffffff8760a01c16804211611884575082871696838803611812575b5050611810955016926118b5565b565b878484161160001461184f57602488604051907ff96fb0710000000000000000000000000000000000000000000000000000000082526004820152fd5b7fffffffffffffffffffffffff000000000000000000000000000000000000000084846118109a031691161790553880611802565b602490604051907fd81b2f2e0000000000000000000000000000000000000000000000000000000082526004820152fd5b9060006064926020958295604051947f23b872dd0000000000000000000000000000000000000000000000000000000086526004860152602485015260448401525af13d15601f3d116001600051141617161561190e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b91908110156117725760061b0190565b3573ffffffffffffffffffffffffffffffffffffffff8116810361149b5790565b9065ffffffffffff908160608401511673ffffffffffffffffffffffffffffffffffffffff908185511694826020820151169280866040809401511695169560009187835260016020528383208984526020528383209916988983526020528282209184835460d01c03611af5579185611ace94927fc6a377bfc4eb120024a8ac08eef205be16b817020812c73223e81d1bdb9708ec98979694508715600014611ad35779ffffffffffff00000000000000000000000000000000000000009042165b60a01b167fffffffffffff00000000000000000000000000000000000000000000000000006001860160d01b1617179055519384938491604091949373ffffffffffffffffffffffffffffffffffffffff606085019616845265ffffffffffff809216602085015216910152565b0390a4565b5079ffffffffffff000000000000000000000000000000000000000087611a60565b600484517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b467f000000000000000000000000000000000000000000000000000000000000000003611b69577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86682527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a604082015246606082015230608082015260808152611bd3816113ff565b51902090565b611be1611b1e565b906040519060208201927f190100000000000000000000000000000000000000000000000000000000000084526022830152604282015260428152611bd381611398565b9192909360a435936040840151804211611cc65750602084510151808611611c955750918591610d78611c6594611c60602088015186611e47565b611bd9565b73ffffffffffffffffffffffffffffffffffffffff809151511692608435918216820361149b57611810936118b5565b602490604051907f3728b83d0000000000000000000000000000000000000000000000000000000082526004820152fd5b602490604051907fcd21db4f0000000000000000000000000000000000000000000000000000000082526004820152fd5b959093958051519560409283830151804211611e175750848803611dee57611d2e918691610d7860209b611c608d88015186611e47565b60005b868110611d42575050505050505050565b611d4d81835161175e565b5188611d5a83878a61196c565b01359089810151808311611dbe575091818888886001968596611d84575b50505050505001611d31565b611db395611dad9273ffffffffffffffffffffffffffffffffffffffff6105159351169561196c565b916118b5565b803888888883611d78565b6024908651907f3728b83d0000000000000000000000000000000000000000000000000000000082526004820152fd5b600484517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b6024908551907fcd21db4f0000000000000000000000000000000000000000000000000000000082526004820152fd5b9073ffffffffffffffffffffffffffffffffffffffff600160ff83161b9216600052600060205260406000209060081c6000526020526040600020818154188091551615611e9157565b60046040517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b90611ec5826115ef565b611ed26040519182611437565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0611f0082946115ef565b0190602036910137565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611f375760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b805160208092019160005b828110611f7f575050505090565b835185529381019392810192600101611f71565b9081519160005b838110611fab575050016000815290565b8060208092840101518185015201611f9a565b60405160208101917f65626cad6cb96493bf6f5ebea28756c966f023ab9e8a83a7101849d5573b3678835273ffffffffffffffffffffffffffffffffffffffff8082511660408401526020820151166060830152606065ffffffffffff9182604082015116608085015201511660a082015260a0815260c0810181811067ffffffffffffffff8211176113b45760405251902090565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a1845273ffffffffffffffffffffffffffffffffffffffff81511660408401520151606082015260608152611bd381611398565b919082604091031261149b576020823592013590565b6000843b61222e5750604182036121ac576120e4828201826120b1565b939092604010156117725760209360009360ff6040608095013560f81c5b60405194855216868401526040830152606082015282805260015afa156121a05773ffffffffffffffffffffffffffffffffffffffff806000511691821561217657160361214c57565b60046040517f815e1d64000000000000000000000000000000000000000000000000000000008152fd5b60046040517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b6040513d6000823e3d90fd5b60408203612204576121c0918101906120b1565b91601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84169360ff1c019060ff8211611f375760209360009360ff608094612102565b60046040517f4be6321b000000000000000000000000000000000000000000000000000000008152fd5b929391601f928173ffffffffffffffffffffffffffffffffffffffff60646020957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0604051988997889687947f1626ba7e000000000000000000000000000000000000000000000000000000009e8f8752600487015260406024870152816044870152868601378b85828601015201168101030192165afa9081156123a857829161232a575b507fffffffff000000000000000000000000000000000000000000000000000000009150160361230057565b60046040517fb0669cbc000000000000000000000000000000000000000000000000000000008152fd5b90506020813d82116123a0575b8161234460209383611437565b810103126103365751907fffffffff0000000000000000000000000000000000000000000000000000000082168203610a9a57507fffffffff0000000000000000000000000000000000000000000000000000000090386122d4565b3d9150612337565b6040513d84823e3d90fdfea164736f6c6343000811000a"); +pub(crate) const PERMIT2_BYTECODE: &[u8] = &hex!("6040608081526004908136101561001557600080fd5b600090813560e01c80630d58b1db1461126c578063137c29fe146110755780632a2d80d114610db75780632b67b57014610bde57806330f28b7a14610ade5780633644e51514610a9d57806336c7851614610a285780633ff9dcb1146109a85780634fe02b441461093f57806365d9723c146107ac57806387517c451461067a578063927da105146105c3578063cc53287f146104a3578063edd9444b1461033a5763fe8ec1a7146100c657600080fd5b346103365760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365767ffffffffffffffff833581811161033257610114903690860161164b565b60243582811161032e5761012b903690870161161a565b6101336114e6565b9160843585811161032a5761014b9036908a016115c1565b98909560a43590811161032657610164913691016115c1565b969095815190610173826113ff565b606b82527f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208301527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c61646472838301527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608301527f3620646561646c696e652c000000000000000000000000000000000000000000608083015282519a8b9181610222602085018096611f93565b918237018a8152039961025b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09b8c8101835282611437565b5190209085515161026b81611ebb565b908a5b8181106102f95750506102f6999a6102ed9183516102a081610294602082018095611f66565b03848101835282611437565b519020602089810151858b015195519182019687526040820192909252336060820152608081019190915260a081019390935260643560c08401528260e081015b03908101835282611437565b51902093611cf7565b80f35b8061031161030b610321938c5161175e565b51612054565b61031b828661175e565b52611f0a565b61026e565b8880fd5b8780fd5b8480fd5b8380fd5b5080fd5b5091346103365760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365767ffffffffffffffff9080358281116103325761038b903690830161164b565b60243583811161032e576103a2903690840161161a565b9390926103ad6114e6565b9160643590811161049f576103c4913691016115c1565b949093835151976103d489611ebb565b98885b81811061047d5750506102f697988151610425816103f9602082018095611f66565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611437565b5190206020860151828701519083519260208401947ffcf35f5ac6a2c28868dc44c302166470266239195f02b0ee408334829333b7668652840152336060840152608083015260a082015260a081526102ed8161141b565b808b61031b8261049461030b61049a968d5161175e565b9261175e565b6103d7565b8680fd5b5082346105bf57602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103325780359067ffffffffffffffff821161032e576104f49136910161161a565b929091845b848110610504578580f35b8061051a610515600193888861196c565b61197c565b61052f84610529848a8a61196c565b0161197c565b3389528385528589209173ffffffffffffffffffffffffffffffffffffffff80911692838b528652868a20911690818a5285528589207fffffffffffffffffffffffff000000000000000000000000000000000000000081541690558551918252848201527f89b1add15eff56b3dfe299ad94e01f2b52fbcb80ae1a3baea6ae8c04cb2b98a4853392a2016104f9565b8280fd5b50346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610676816105ff6114a0565b936106086114c3565b6106106114e6565b73ffffffffffffffffffffffffffffffffffffffff968716835260016020908152848420928816845291825283832090871683528152919020549251938316845260a083901c65ffffffffffff169084015260d09190911c604083015281906060820190565b0390f35b50346103365760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576106b26114a0565b906106bb6114c3565b916106c46114e6565b65ffffffffffff926064358481169081810361032a5779ffffffffffff0000000000000000000000000000000000000000947fda9fa7c1b00402c17d0161b249b1ab8bbec047c5a52207b9c112deffd817036b94338a5260016020527fffffffffffff0000000000000000000000000000000000000000000000000000858b209873ffffffffffffffffffffffffffffffffffffffff809416998a8d5260205283878d209b169a8b8d52602052868c209486156000146107a457504216925b8454921697889360a01b16911617179055815193845260208401523392a480f35b905092610783565b5082346105bf5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf576107e56114a0565b906107ee6114c3565b9265ffffffffffff604435818116939084810361032a57338852602091600183528489209673ffffffffffffffffffffffffffffffffffffffff80911697888b528452858a20981697888a5283528489205460d01c93848711156109175761ffff9085840316116108f05750907f55eb90d810e1700b35a8e7e25395ff7f2b2259abd7415ca2284dfb1c246418f393929133895260018252838920878a528252838920888a5282528389209079ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffff000000000000000000000000000000000000000000000000000083549260d01b16911617905582519485528401523392a480f35b84517f24d35a26000000000000000000000000000000000000000000000000000000008152fd5b5084517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b503461033657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336578060209273ffffffffffffffffffffffffffffffffffffffff61098f6114a0565b1681528084528181206024358252845220549051908152f35b5082346105bf57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf577f3704902f963766a4e561bbaab6e6cdc1b1dd12f6e9e99648da8843b3f46b918d90359160243533855284602052818520848652602052818520818154179055815193845260208401523392a280f35b8234610a9a5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610a9a57610a606114a0565b610a686114c3565b610a706114e6565b6064359173ffffffffffffffffffffffffffffffffffffffff8316830361032e576102f6936117a1565b80fd5b503461033657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602090610ad7611b1e565b9051908152f35b508290346105bf576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf57610b1a3661152a565b90807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c36011261033257610b4c611478565b9160e43567ffffffffffffffff8111610bda576102f694610b6f913691016115c1565b939092610b7c8351612054565b6020840151828501519083519260208401947f939c21a48a8dbe3a9a2404a1d46691e4d39f6583d6ec6b35714604c986d801068652840152336060840152608083015260a082015260a08152610bd18161141b565b51902091611c25565b8580fd5b509134610336576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610c186114a0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc360160c08112610332576080855191610c51836113e3565b1261033257845190610c6282611398565b73ffffffffffffffffffffffffffffffffffffffff91602435838116810361049f578152604435838116810361049f57602082015265ffffffffffff606435818116810361032a5788830152608435908116810361049f576060820152815260a435938285168503610bda576020820194855260c4359087830182815260e43567ffffffffffffffff811161032657610cfe90369084016115c1565b929093804211610d88575050918591610d786102f6999a610d7e95610d238851611fbe565b90898c511690519083519260208401947ff3841cd1ff0085026a6327b620b67997ce40f282c88a8e905a7a5626e310f3d086528401526060830152608082015260808152610d70816113ff565b519020611bd9565b916120c7565b519251169161199d565b602492508a51917fcd21db4f000000000000000000000000000000000000000000000000000000008352820152fd5b5091346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc93818536011261033257610df36114a0565b9260249081359267ffffffffffffffff9788851161032a578590853603011261049f578051978589018981108282111761104a578252848301358181116103265785019036602383011215610326578382013591610e50836115ef565b90610e5d85519283611437565b838252602093878584019160071b83010191368311611046578801905b828210610fe9575050508a526044610e93868801611509565b96838c01978852013594838b0191868352604435908111610fe557610ebb90369087016115c1565b959096804211610fba575050508998995151610ed681611ebb565b908b5b818110610f9757505092889492610d7892610f6497958351610f02816103f98682018095611f66565b5190209073ffffffffffffffffffffffffffffffffffffffff9a8b8b51169151928551948501957faf1b0d30d2cab0380e68f0689007e3254993c596f2fdd0aaa7f4d04f794408638752850152830152608082015260808152610d70816113ff565b51169082515192845b848110610f78578580f35b80610f918585610f8b600195875161175e565b5161199d565b01610f6d565b80610311610fac8e9f9e93610fb2945161175e565b51611fbe565b9b9a9b610ed9565b8551917fcd21db4f000000000000000000000000000000000000000000000000000000008352820152fd5b8a80fd5b6080823603126110465785608091885161100281611398565b61100b85611509565b8152611018838601611509565b838201526110278a8601611607565b8a8201528d611037818701611607565b90820152815201910190610e7a565b8c80fd5b84896041867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5082346105bf576101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf576110b03661152a565b91807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c360112610332576110e2611478565b67ffffffffffffffff93906101043585811161049f5761110590369086016115c1565b90936101243596871161032a57611125610bd1966102f6983691016115c1565b969095825190611134826113ff565b606482527f5065726d69745769746e6573735472616e7366657246726f6d28546f6b656e5060208301527f65726d697373696f6e73207065726d69747465642c6164647265737320737065848301527f6e6465722c75696e74323536206e6f6e63652c75696e7432353620646561646c60608301527f696e652c0000000000000000000000000000000000000000000000000000000060808301528351948591816111e3602085018096611f93565b918237018b8152039361121c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868101835282611437565b5190209261122a8651612054565b6020878101518589015195519182019687526040820192909252336060820152608081019190915260a081019390935260e43560c08401528260e081016102e1565b5082346105bf576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033257813567ffffffffffffffff92838211610bda5736602383011215610bda5781013592831161032e576024906007368386831b8401011161049f57865b8581106112e5578780f35b80821b83019060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc83360301126103265761139288876001946060835161132c81611398565b611368608461133c8d8601611509565b9485845261134c60448201611509565b809785015261135d60648201611509565b809885015201611509565b918291015273ffffffffffffffffffffffffffffffffffffffff80808093169516931691166117a1565b016112da565b6080810190811067ffffffffffffffff8211176113b457604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff8211176113b457604052565b60a0810190811067ffffffffffffffff8211176113b457604052565b60c0810190811067ffffffffffffffff8211176113b457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176113b457604052565b60c4359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b600080fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc01906080821261149b576040805190611563826113e3565b8082941261149b57805181810181811067ffffffffffffffff8211176113b457825260043573ffffffffffffffffffffffffffffffffffffffff8116810361149b578152602435602082015282526044356020830152606435910152565b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020838186019501011161149b57565b67ffffffffffffffff81116113b45760051b60200190565b359065ffffffffffff8216820361149b57565b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020808501948460061b01011161149b57565b91909160608184031261149b576040805191611666836113e3565b8294813567ffffffffffffffff9081811161149b57830182601f8201121561149b578035611693816115ef565b926116a087519485611437565b818452602094858086019360061b8501019381851161149b579086899897969594939201925b8484106116e3575050505050855280820135908501520135910152565b90919293949596978483031261149b578851908982019082821085831117611730578a928992845261171487611509565b81528287013583820152815201930191908897969594936116c6565b602460007f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b80518210156117725760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b92919273ffffffffffffffffffffffffffffffffffffffff604060008284168152600160205282828220961695868252602052818120338252602052209485549565ffffffffffff8760a01c16804211611884575082871696838803611812575b5050611810955016926118b5565b565b878484161160001461184f57602488604051907ff96fb0710000000000000000000000000000000000000000000000000000000082526004820152fd5b7fffffffffffffffffffffffff000000000000000000000000000000000000000084846118109a031691161790553880611802565b602490604051907fd81b2f2e0000000000000000000000000000000000000000000000000000000082526004820152fd5b9060006064926020958295604051947f23b872dd0000000000000000000000000000000000000000000000000000000086526004860152602485015260448401525af13d15601f3d116001600051141617161561190e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b91908110156117725760061b0190565b3573ffffffffffffffffffffffffffffffffffffffff8116810361149b5790565b9065ffffffffffff908160608401511673ffffffffffffffffffffffffffffffffffffffff908185511694826020820151169280866040809401511695169560009187835260016020528383208984526020528383209916988983526020528282209184835460d01c03611af5579185611ace94927fc6a377bfc4eb120024a8ac08eef205be16b817020812c73223e81d1bdb9708ec98979694508715600014611ad35779ffffffffffff00000000000000000000000000000000000000009042165b60a01b167fffffffffffff00000000000000000000000000000000000000000000000000006001860160d01b1617179055519384938491604091949373ffffffffffffffffffffffffffffffffffffffff606085019616845265ffffffffffff809216602085015216910152565b0390a4565b5079ffffffffffff000000000000000000000000000000000000000087611a60565b600484517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b467f000000000000000000000000000000000000000000000000000000000000000003611b69577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86682527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a604082015246606082015230608082015260808152611bd3816113ff565b51902090565b611be1611b1e565b906040519060208201927f190100000000000000000000000000000000000000000000000000000000000084526022830152604282015260428152611bd381611398565b9192909360a435936040840151804211611cc65750602084510151808611611c955750918591610d78611c6594611c60602088015186611e47565b611bd9565b73ffffffffffffffffffffffffffffffffffffffff809151511692608435918216820361149b57611810936118b5565b602490604051907f3728b83d0000000000000000000000000000000000000000000000000000000082526004820152fd5b602490604051907fcd21db4f0000000000000000000000000000000000000000000000000000000082526004820152fd5b959093958051519560409283830151804211611e175750848803611dee57611d2e918691610d7860209b611c608d88015186611e47565b60005b868110611d42575050505050505050565b611d4d81835161175e565b5188611d5a83878a61196c565b01359089810151808311611dbe575091818888886001968596611d84575b50505050505001611d31565b611db395611dad9273ffffffffffffffffffffffffffffffffffffffff6105159351169561196c565b916118b5565b803888888883611d78565b6024908651907f3728b83d0000000000000000000000000000000000000000000000000000000082526004820152fd5b600484517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b6024908551907fcd21db4f0000000000000000000000000000000000000000000000000000000082526004820152fd5b9073ffffffffffffffffffffffffffffffffffffffff600160ff83161b9216600052600060205260406000209060081c6000526020526040600020818154188091551615611e9157565b60046040517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b90611ec5826115ef565b611ed26040519182611437565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0611f0082946115ef565b0190602036910137565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611f375760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b805160208092019160005b828110611f7f575050505090565b835185529381019392810192600101611f71565b9081519160005b838110611fab575050016000815290565b8060208092840101518185015201611f9a565b60405160208101917f65626cad6cb96493bf6f5ebea28756c966f023ab9e8a83a7101849d5573b3678835273ffffffffffffffffffffffffffffffffffffffff8082511660408401526020820151166060830152606065ffffffffffff9182604082015116608085015201511660a082015260a0815260c0810181811067ffffffffffffffff8211176113b45760405251902090565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a1845273ffffffffffffffffffffffffffffffffffffffff81511660408401520151606082015260608152611bd381611398565b919082604091031261149b576020823592013590565b6000843b61222e5750604182036121ac576120e4828201826120b1565b939092604010156117725760209360009360ff6040608095013560f81c5b60405194855216868401526040830152606082015282805260015afa156121a05773ffffffffffffffffffffffffffffffffffffffff806000511691821561217657160361214c57565b60046040517f815e1d64000000000000000000000000000000000000000000000000000000008152fd5b60046040517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b6040513d6000823e3d90fd5b60408203612204576121c0918101906120b1565b91601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84169360ff1c019060ff8211611f375760209360009360ff608094612102565b60046040517f4be6321b000000000000000000000000000000000000000000000000000000008152fd5b929391601f928173ffffffffffffffffffffffffffffffffffffffff60646020957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0604051988997889687947f1626ba7e000000000000000000000000000000000000000000000000000000009e8f8752600487015260406024870152816044870152868601378b85828601015201168101030192165afa9081156123a857829161232a575b507fffffffff000000000000000000000000000000000000000000000000000000009150160361230057565b60046040517fb0669cbc000000000000000000000000000000000000000000000000000000008152fd5b90506020813d82116123a0575b8161234460209383611437565b810103126103365751907fffffffff0000000000000000000000000000000000000000000000000000000082168203610a9a57507fffffffff0000000000000000000000000000000000000000000000000000000090386122d4565b3d9150612337565b6040513d84823e3d90fdfea164736f6c6343000811000a"); // ── Immutable reference offsets (from compiled artifact `immutableReferences`) ── /// `_CACHED_CHAIN_ID` (uint256) — from `EIP712.sol`. -const CACHED_CHAIN_ID_REFS: &[ImmutableRef] = &[ImmutableRef { +pub(crate) const CACHED_CHAIN_ID_REFS: &[ImmutableRef] = &[ImmutableRef { start: 6945, length: 32, }]; /// `_CACHED_DOMAIN_SEPARATOR` (bytes32) — from `EIP712.sol`. -const CACHED_DOMAIN_SEPARATOR_REFS: &[ImmutableRef] = &[ImmutableRef { +pub(crate) const CACHED_DOMAIN_SEPARATOR_REFS: &[ImmutableRef] = &[ImmutableRef { start: 6983, length: 32, }]; /// EIP-712 type hash: `keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)")` -const EIP712_TYPE_HASH: B256 = B256::new(hex!( +pub(crate) const EIP712_TYPE_HASH: B256 = B256::new(hex!( "8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866" )); /// `keccak256("Permit2")` -const HASHED_NAME: B256 = B256::new(hex!( +pub(crate) const HASHED_NAME: B256 = B256::new(hex!( "9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a" )); -/// Build a genesis alloc entry for `Permit2`. -pub(crate) fn build(config: &Permit2Config, chain_id: u64) -> GenesisContract { +/// Build the expected runtime bytecode for a Permit2 deployed at `address` on `chain_id`. +/// Used by the deploy pipeline to verify on-chain bytecode matches. +pub(crate) fn expected_runtime_bytecode(chain_id: u64, address: Address) -> Vec { let mut bytecode = PERMIT2_BYTECODE.to_vec(); - // Patch _CACHED_CHAIN_ID let chain_id_u256 = U256::from(chain_id); patch_u256(&mut bytecode, CACHED_CHAIN_ID_REFS, chain_id_u256); - // Compute and patch _CACHED_DOMAIN_SEPARATOR: - // keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, chainId, contractAddress)) let mut buf = [0u8; 128]; buf[0..32].copy_from_slice(EIP712_TYPE_HASH.as_slice()); buf[32..64].copy_from_slice(HASHED_NAME.as_slice()); buf[64..96].copy_from_slice(&B256::from(chain_id_u256).0); - buf[96..128].copy_from_slice(config.address.into_word().as_slice()); + buf[96..128].copy_from_slice(address.into_word().as_slice()); let domain_separator = keccak256(buf); patch_bytes( &mut bytecode, @@ -89,8 +87,16 @@ pub(crate) fn build(config: &Permit2Config, chain_id: u64) -> GenesisContract { &domain_separator.0, ); + bytecode +} + +/// Build a genesis alloc entry for `Permit2`. +pub(crate) fn build(config: &Permit2Config, chain_id: u64) -> GenesisContract { + let address = config.address.expect("address required for genesis"); + let bytecode = expected_runtime_bytecode(chain_id, address); + GenesisContract { - address: config.address, + address, code: Bytes::from(bytecode), storage: BTreeMap::new(), } @@ -104,7 +110,7 @@ mod tests { fn test_config() -> Permit2Config { Permit2Config { - address: address!("000000000022D473030F116dDEE9F6B43aC78BA3"), + address: Some(address!("000000000022D473030F116dDEE9F6B43aC78BA3")), } } @@ -138,7 +144,7 @@ mod tests { buf[0..32].copy_from_slice(EIP712_TYPE_HASH.as_slice()); buf[32..64].copy_from_slice(HASHED_NAME.as_slice()); buf[64..96].copy_from_slice(&B256::from(U256::from(chain_id)).0); - buf[96..128].copy_from_slice(config.address.into_word().as_slice()); + buf[96..128].copy_from_slice(config.address.unwrap().into_word().as_slice()); let expected = keccak256(buf); let word = &code[6983..6983 + 32]; @@ -163,13 +169,13 @@ mod tests { fn domain_separator_changes_with_address() { let c1 = build( &Permit2Config { - address: Address::repeat_byte(0x01), + address: Some(Address::repeat_byte(0x01)), }, 1234, ); let c2 = build( &Permit2Config { - address: Address::repeat_byte(0x02), + address: Some(Address::repeat_byte(0x02)), }, 1234, ); diff --git a/bin/ev-deployer/src/genesis.rs b/bin/ev-deployer/src/genesis.rs index e270b69..322f8ca 100644 --- a/bin/ev-deployer/src/genesis.rs +++ b/bin/ev-deployer/src/genesis.rs @@ -104,7 +104,7 @@ mod tests { chain: ChainConfig { chain_id: 1234 }, contracts: ContractsConfig { admin_proxy: Some(AdminProxyConfig { - address: address!("000000000000000000000000000000000000ad00"), + address: Some(address!("000000000000000000000000000000000000ad00")), owner: address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), }), permit2: None, diff --git a/bin/ev-deployer/src/main.rs b/bin/ev-deployer/src/main.rs index 5d87ae9..8ad8d7d 100644 --- a/bin/ev-deployer/src/main.rs +++ b/bin/ev-deployer/src/main.rs @@ -73,6 +73,7 @@ fn main() -> eyre::Result<()> { addresses_out, } => { let cfg = config::DeployConfig::load(&config_path)?; + cfg.validate_for_genesis()?; let result = if let Some(ref genesis_path) = merge_into { genesis::merge_into(&cfg, genesis_path, force)? @@ -117,14 +118,14 @@ fn main() -> eyre::Result<()> { .contracts .admin_proxy .as_ref() - .map(|c| c.address) - .ok_or_else(|| eyre::eyre!("admin_proxy not configured"))?, + .and_then(|c| c.address) + .ok_or_else(|| eyre::eyre!("admin_proxy not configured or address not set"))?, "permit2" => cfg .contracts .permit2 .as_ref() - .map(|c| c.address) - .ok_or_else(|| eyre::eyre!("permit2 not configured"))?, + .and_then(|c| c.address) + .ok_or_else(|| eyre::eyre!("permit2 not configured or address not set"))?, other => eyre::bail!("unknown contract: {other}"), }; diff --git a/bin/ev-deployer/src/output.rs b/bin/ev-deployer/src/output.rs index f683377..d434974 100644 --- a/bin/ev-deployer/src/output.rs +++ b/bin/ev-deployer/src/output.rs @@ -8,17 +8,21 @@ pub(crate) fn build_manifest(config: &DeployConfig) -> Value { let mut manifest = Map::new(); if let Some(ref ap) = config.contracts.admin_proxy { - manifest.insert( - "admin_proxy".to_string(), - Value::String(format!("{}", ap.address)), - ); + if let Some(addr) = ap.address { + manifest.insert( + "admin_proxy".to_string(), + Value::String(format!("{}", addr)), + ); + } } if let Some(ref p2) = config.contracts.permit2 { - manifest.insert( - "permit2".to_string(), - Value::String(format!("{}", p2.address)), - ); + if let Some(addr) = p2.address { + manifest.insert( + "permit2".to_string(), + Value::String(format!("{}", addr)), + ); + } } Value::Object(manifest) From 3c74168798e9f36e3b2fc01ca481de1657b910ce Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 17:17:35 +0200 Subject: [PATCH 02/18] feat(ev-deployer): add initcode constants for live deployment Embeds creation bytecodes alongside existing runtime bytecodes. Extracts expected_runtime_bytecode for Permit2 verification. --- bin/ev-deployer/src/contracts/admin_proxy.rs | 5 +++++ bin/ev-deployer/src/contracts/permit2.rs | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/bin/ev-deployer/src/contracts/admin_proxy.rs b/bin/ev-deployer/src/contracts/admin_proxy.rs index 33c4f54..4709eb0 100644 --- a/bin/ev-deployer/src/contracts/admin_proxy.rs +++ b/bin/ev-deployer/src/contracts/admin_proxy.rs @@ -7,6 +7,11 @@ use std::collections::BTreeMap; /// `AdminProxy` runtime bytecode compiled with solc 0.8.33 (`cbor_metadata=false`). /// Regenerate with: `cd contracts && forge inspect AdminProxy deployedBytecode` pub(crate) const ADMIN_PROXY_BYTECODE: &[u8] = &hex!("60806040526004361061007e575f3560e01c80638da5cb5b1161004d5780638da5cb5b1461012d578063e30c397814610157578063f2fde38b14610181578063fa4bb79d146101a957610085565b806318dfb3c7146100895780631cff79cd146100c557806379ba5097146101015780638b5298541461011757610085565b3661008557005b5f5ffd5b348015610094575f5ffd5b506100af60048036038101906100aa9190610cf8565b6101e5565b6040516100bc9190610ea1565b60405180910390f35b3480156100d0575f5ffd5b506100eb60048036038101906100e69190610f70565b6104d9565b6040516100f89190611015565b60405180910390f35b34801561010c575f5ffd5b5061011561066c565b005b348015610122575f5ffd5b5061012b6107ed565b005b348015610138575f5ffd5b506101416108b4565b60405161014e9190611044565b60405180910390f35b348015610162575f5ffd5b5061016b6108d8565b6040516101789190611044565b60405180910390f35b34801561018c575f5ffd5b506101a760048036038101906101a2919061105d565b6108fd565b005b3480156101b4575f5ffd5b506101cf60048036038101906101ca91906110bb565b610aa4565b6040516101dc9190611015565b60405180910390f35b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026c576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282905085859050146102ab576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484905067ffffffffffffffff8111156102c8576102c761112c565b5b6040519080825280602002602001820160405280156102fb57816020015b60608152602001906001900390816102e65790505b5090505f5f90505b858590508110156104d0575f5f87878481811061032357610322611159565b5b9050602002016020810190610338919061105d565b73ffffffffffffffffffffffffffffffffffffffff1686868581811061036157610360611159565b5b90506020028101906103739190611192565b604051610381929190611230565b5f604051808303815f865af19150503d805f81146103ba576040519150601f19603f3d011682016040523d82523d5f602084013e6103bf565b606091505b50915091508161040657806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016103fd9190611015565b60405180910390fd5b87878481811061041957610418611159565b5b905060200201602081019061042e919061105d565b73ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb587878681811061047857610477611159565b5b905060200281019061048a9190611192565b8460405161049a93929190611274565b60405180910390a2808484815181106104b6576104b5611159565b5b602002602001018190525050508080600101915050610303565b50949350505050565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610560576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8573ffffffffffffffffffffffffffffffffffffffff168585604051610589929190611230565b5f604051808303815f865af19150503d805f81146105c2576040519150601f19603f3d011682016040523d82523d5f602084013e6105c7565b606091505b50915091508161060e57806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016106059190611015565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb586868460405161065893929190611274565b60405180910390a280925050509392505050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106f2576040517f1853971c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3335f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610872576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610982576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036109e7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b2b576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff16848787604051610b55929190611230565b5f6040518083038185875af1925050503d805f8114610b8f576040519150601f19603f3d011682016040523d82523d5f602084013e610b94565b606091505b509150915081610bdb57806040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152600401610bd29190611015565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb5878784604051610c2593929190611274565b60405180910390a28092505050949350505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112610c6357610c62610c42565b5b8235905067ffffffffffffffff811115610c8057610c7f610c46565b5b602083019150836020820283011115610c9c57610c9b610c4a565b5b9250929050565b5f5f83601f840112610cb857610cb7610c42565b5b8235905067ffffffffffffffff811115610cd557610cd4610c46565b5b602083019150836020820283011115610cf157610cf0610c4a565b5b9250929050565b5f5f5f5f60408587031215610d1057610d0f610c3a565b5b5f85013567ffffffffffffffff811115610d2d57610d2c610c3e565b5b610d3987828801610c4e565b9450945050602085013567ffffffffffffffff811115610d5c57610d5b610c3e565b5b610d6887828801610ca3565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610de182610d9f565b610deb8185610da9565b9350610dfb818560208601610db9565b610e0481610dc7565b840191505092915050565b5f610e1a8383610dd7565b905092915050565b5f602082019050919050565b5f610e3882610d76565b610e428185610d80565b935083602082028501610e5485610d90565b805f5b85811015610e8f5784840389528151610e708582610e0f565b9450610e7b83610e22565b925060208a01995050600181019050610e57565b50829750879550505050505092915050565b5f6020820190508181035f830152610eb98184610e2e565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610eea82610ec1565b9050919050565b610efa81610ee0565b8114610f04575f5ffd5b50565b5f81359050610f1581610ef1565b92915050565b5f5f83601f840112610f3057610f2f610c42565b5b8235905067ffffffffffffffff811115610f4d57610f4c610c46565b5b602083019150836001820283011115610f6957610f68610c4a565b5b9250929050565b5f5f5f60408486031215610f8757610f86610c3a565b5b5f610f9486828701610f07565b935050602084013567ffffffffffffffff811115610fb557610fb4610c3e565b5b610fc186828701610f1b565b92509250509250925092565b5f82825260208201905092915050565b5f610fe782610d9f565b610ff18185610fcd565b9350611001818560208601610db9565b61100a81610dc7565b840191505092915050565b5f6020820190508181035f83015261102d8184610fdd565b905092915050565b61103e81610ee0565b82525050565b5f6020820190506110575f830184611035565b92915050565b5f6020828403121561107257611071610c3a565b5b5f61107f84828501610f07565b91505092915050565b5f819050919050565b61109a81611088565b81146110a4575f5ffd5b50565b5f813590506110b581611091565b92915050565b5f5f5f5f606085870312156110d3576110d2610c3a565b5b5f6110e087828801610f07565b945050602085013567ffffffffffffffff81111561110157611100610c3e565b5b61110d87828801610f1b565b93509350506040611120878288016110a7565b91505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126111ae576111ad611186565b5b80840192508235915067ffffffffffffffff8211156111d0576111cf61118a565b5b6020830192506001820236038313156111ec576111eb61118e565b5b509250929050565b5f81905092915050565b828183375f83830152505050565b5f61121783856111f4565b93506112248385846111fe565b82840190509392505050565b5f61123c82848661120c565b91508190509392505050565b5f6112538385610fcd565b93506112608385846111fe565b61126983610dc7565b840190509392505050565b5f6040820190508181035f83015261128d818587611248565b905081810360208301526112a18184610fdd565b905094935050505056"); +/// `AdminProxy` creation bytecode (initcode) compiled with solc 0.8.33 (`cbor_metadata=false`). +/// The constructor is empty; owner is set via storage, not constructor args. +/// Regenerate with: `cd contracts && forge inspect AdminProxy bytecode` +pub(crate) const ADMIN_PROXY_INITCODE: &[u8] = &hex!("6080604052348015600e575f5ffd5b506112ab8061001c5f395ff3fe60806040526004361061007e575f3560e01c80638da5cb5b1161004d5780638da5cb5b1461012d578063e30c397814610157578063f2fde38b14610181578063fa4bb79d146101a957610085565b806318dfb3c7146100895780631cff79cd146100c557806379ba5097146101015780638b5298541461011757610085565b3661008557005b5f5ffd5b348015610094575f5ffd5b506100af60048036038101906100aa9190610cf8565b6101e5565b6040516100bc9190610ea1565b60405180910390f35b3480156100d0575f5ffd5b506100eb60048036038101906100e69190610f70565b6104d9565b6040516100f89190611015565b60405180910390f35b34801561010c575f5ffd5b5061011561066c565b005b348015610122575f5ffd5b5061012b6107ed565b005b348015610138575f5ffd5b506101416108b4565b60405161014e9190611044565b60405180910390f35b348015610162575f5ffd5b5061016b6108d8565b6040516101789190611044565b60405180910390f35b34801561018c575f5ffd5b506101a760048036038101906101a2919061105d565b6108fd565b005b3480156101b4575f5ffd5b506101cf60048036038101906101ca91906110bb565b610aa4565b6040516101dc9190611015565b60405180910390f35b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026c576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282905085859050146102ab576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484905067ffffffffffffffff8111156102c8576102c761112c565b5b6040519080825280602002602001820160405280156102fb57816020015b60608152602001906001900390816102e65790505b5090505f5f90505b858590508110156104d0575f5f87878481811061032357610322611159565b5b9050602002016020810190610338919061105d565b73ffffffffffffffffffffffffffffffffffffffff1686868581811061036157610360611159565b5b90506020028101906103739190611192565b604051610381929190611230565b5f604051808303815f865af19150503d805f81146103ba576040519150601f19603f3d011682016040523d82523d5f602084013e6103bf565b606091505b50915091508161040657806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016103fd9190611015565b60405180910390fd5b87878481811061041957610418611159565b5b905060200201602081019061042e919061105d565b73ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb587878681811061047857610477611159565b5b905060200281019061048a9190611192565b8460405161049a93929190611274565b60405180910390a2808484815181106104b6576104b5611159565b5b602002602001018190525050508080600101915050610303565b50949350505050565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610560576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8573ffffffffffffffffffffffffffffffffffffffff168585604051610589929190611230565b5f604051808303815f865af19150503d805f81146105c2576040519150601f19603f3d011682016040523d82523d5f602084013e6105c7565b606091505b50915091508161060e57806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016106059190611015565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb586868460405161065893929190611274565b60405180910390a280925050509392505050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106f2576040517f1853971c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3335f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610872576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610982576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036109e7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b2b576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff16848787604051610b55929190611230565b5f6040518083038185875af1925050503d805f8114610b8f576040519150601f19603f3d011682016040523d82523d5f602084013e610b94565b606091505b509150915081610bdb57806040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152600401610bd29190611015565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb5878784604051610c2593929190611274565b60405180910390a28092505050949350505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112610c6357610c62610c42565b5b8235905067ffffffffffffffff811115610c8057610c7f610c46565b5b602083019150836020820283011115610c9c57610c9b610c4a565b5b9250929050565b5f5f83601f840112610cb857610cb7610c42565b5b8235905067ffffffffffffffff811115610cd557610cd4610c46565b5b602083019150836020820283011115610cf157610cf0610c4a565b5b9250929050565b5f5f5f5f60408587031215610d1057610d0f610c3a565b5b5f85013567ffffffffffffffff811115610d2d57610d2c610c3e565b5b610d3987828801610c4e565b9450945050602085013567ffffffffffffffff811115610d5c57610d5b610c3e565b5b610d6887828801610ca3565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610de182610d9f565b610deb8185610da9565b9350610dfb818560208601610db9565b610e0481610dc7565b840191505092915050565b5f610e1a8383610dd7565b905092915050565b5f602082019050919050565b5f610e3882610d76565b610e428185610d80565b935083602082028501610e5485610d90565b805f5b85811015610e8f5784840389528151610e708582610e0f565b9450610e7b83610e22565b925060208a01995050600181019050610e57565b50829750879550505050505092915050565b5f6020820190508181035f830152610eb98184610e2e565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610eea82610ec1565b9050919050565b610efa81610ee0565b8114610f04575f5ffd5b50565b5f81359050610f1581610ef1565b92915050565b5f5f83601f840112610f3057610f2f610c42565b5b8235905067ffffffffffffffff811115610f4d57610f4c610c46565b5b602083019150836001820283011115610f6957610f68610c4a565b5b9250929050565b5f5f5f60408486031215610f8757610f86610c3a565b5b5f610f9486828701610f07565b935050602084013567ffffffffffffffff811115610fb557610fb4610c3e565b5b610fc186828701610f1b565b92509250509250925092565b5f82825260208201905092915050565b5f610fe782610d9f565b610ff18185610fcd565b9350611001818560208601610db9565b61100a81610dc7565b840191505092915050565b5f6020820190508181035f83015261102d8184610fdd565b905092915050565b61103e81610ee0565b82525050565b5f6020820190506110575f830184611035565b92915050565b5f6020828403121561107257611071610c3a565b5b5f61107f84828501610f07565b91505092915050565b5f819050919050565b61109a81611088565b81146110a4575f5ffd5b50565b5f813590506110b581611091565b92915050565b5f5f5f5f606085870312156110d3576110d2610c3a565b5b5f6110e087828801610f07565b945050602085013567ffffffffffffffff81111561110157611100610c3e565b5b61110d87828801610f1b565b93509350506040611120878288016110a7565b91505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126111ae576111ad611186565b5b80840192508235915067ffffffffffffffff8211156111d0576111cf61118a565b5b6020830192506001820236038313156111ec576111eb61118e565b5b509250929050565b5f81905092915050565b828183375f83830152505050565b5f61121783856111f4565b93506112248385846111fe565b82840190509392505050565b5f61123c82848661120c565b91508190509392505050565b5f6112538385610fcd565b93506112608385846111fe565b61126983610dc7565b840190509392505050565b5f6040820190508181035f83015261128d818587611248565b905081810360208301526112a18184610fdd565b905094935050505056"); + /// Build a genesis alloc entry for `AdminProxy`. pub(crate) fn build(config: &AdminProxyConfig) -> GenesisContract { diff --git a/bin/ev-deployer/src/contracts/permit2.rs b/bin/ev-deployer/src/contracts/permit2.rs index ef438b1..eabbbe7 100644 --- a/bin/ev-deployer/src/contracts/permit2.rs +++ b/bin/ev-deployer/src/contracts/permit2.rs @@ -43,6 +43,12 @@ use std::collections::BTreeMap; /// ``` pub(crate) const PERMIT2_BYTECODE: &[u8] = &hex!("6040608081526004908136101561001557600080fd5b600090813560e01c80630d58b1db1461126c578063137c29fe146110755780632a2d80d114610db75780632b67b57014610bde57806330f28b7a14610ade5780633644e51514610a9d57806336c7851614610a285780633ff9dcb1146109a85780634fe02b441461093f57806365d9723c146107ac57806387517c451461067a578063927da105146105c3578063cc53287f146104a3578063edd9444b1461033a5763fe8ec1a7146100c657600080fd5b346103365760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365767ffffffffffffffff833581811161033257610114903690860161164b565b60243582811161032e5761012b903690870161161a565b6101336114e6565b9160843585811161032a5761014b9036908a016115c1565b98909560a43590811161032657610164913691016115c1565b969095815190610173826113ff565b606b82527f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208301527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c61646472838301527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608301527f3620646561646c696e652c000000000000000000000000000000000000000000608083015282519a8b9181610222602085018096611f93565b918237018a8152039961025b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09b8c8101835282611437565b5190209085515161026b81611ebb565b908a5b8181106102f95750506102f6999a6102ed9183516102a081610294602082018095611f66565b03848101835282611437565b519020602089810151858b015195519182019687526040820192909252336060820152608081019190915260a081019390935260643560c08401528260e081015b03908101835282611437565b51902093611cf7565b80f35b8061031161030b610321938c5161175e565b51612054565b61031b828661175e565b52611f0a565b61026e565b8880fd5b8780fd5b8480fd5b8380fd5b5080fd5b5091346103365760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365767ffffffffffffffff9080358281116103325761038b903690830161164b565b60243583811161032e576103a2903690840161161a565b9390926103ad6114e6565b9160643590811161049f576103c4913691016115c1565b949093835151976103d489611ebb565b98885b81811061047d5750506102f697988151610425816103f9602082018095611f66565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611437565b5190206020860151828701519083519260208401947ffcf35f5ac6a2c28868dc44c302166470266239195f02b0ee408334829333b7668652840152336060840152608083015260a082015260a081526102ed8161141b565b808b61031b8261049461030b61049a968d5161175e565b9261175e565b6103d7565b8680fd5b5082346105bf57602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103325780359067ffffffffffffffff821161032e576104f49136910161161a565b929091845b848110610504578580f35b8061051a610515600193888861196c565b61197c565b61052f84610529848a8a61196c565b0161197c565b3389528385528589209173ffffffffffffffffffffffffffffffffffffffff80911692838b528652868a20911690818a5285528589207fffffffffffffffffffffffff000000000000000000000000000000000000000081541690558551918252848201527f89b1add15eff56b3dfe299ad94e01f2b52fbcb80ae1a3baea6ae8c04cb2b98a4853392a2016104f9565b8280fd5b50346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610676816105ff6114a0565b936106086114c3565b6106106114e6565b73ffffffffffffffffffffffffffffffffffffffff968716835260016020908152848420928816845291825283832090871683528152919020549251938316845260a083901c65ffffffffffff169084015260d09190911c604083015281906060820190565b0390f35b50346103365760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576106b26114a0565b906106bb6114c3565b916106c46114e6565b65ffffffffffff926064358481169081810361032a5779ffffffffffff0000000000000000000000000000000000000000947fda9fa7c1b00402c17d0161b249b1ab8bbec047c5a52207b9c112deffd817036b94338a5260016020527fffffffffffff0000000000000000000000000000000000000000000000000000858b209873ffffffffffffffffffffffffffffffffffffffff809416998a8d5260205283878d209b169a8b8d52602052868c209486156000146107a457504216925b8454921697889360a01b16911617179055815193845260208401523392a480f35b905092610783565b5082346105bf5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf576107e56114a0565b906107ee6114c3565b9265ffffffffffff604435818116939084810361032a57338852602091600183528489209673ffffffffffffffffffffffffffffffffffffffff80911697888b528452858a20981697888a5283528489205460d01c93848711156109175761ffff9085840316116108f05750907f55eb90d810e1700b35a8e7e25395ff7f2b2259abd7415ca2284dfb1c246418f393929133895260018252838920878a528252838920888a5282528389209079ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffff000000000000000000000000000000000000000000000000000083549260d01b16911617905582519485528401523392a480f35b84517f24d35a26000000000000000000000000000000000000000000000000000000008152fd5b5084517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b503461033657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336578060209273ffffffffffffffffffffffffffffffffffffffff61098f6114a0565b1681528084528181206024358252845220549051908152f35b5082346105bf57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf577f3704902f963766a4e561bbaab6e6cdc1b1dd12f6e9e99648da8843b3f46b918d90359160243533855284602052818520848652602052818520818154179055815193845260208401523392a280f35b8234610a9a5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610a9a57610a606114a0565b610a686114c3565b610a706114e6565b6064359173ffffffffffffffffffffffffffffffffffffffff8316830361032e576102f6936117a1565b80fd5b503461033657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602090610ad7611b1e565b9051908152f35b508290346105bf576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf57610b1a3661152a565b90807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c36011261033257610b4c611478565b9160e43567ffffffffffffffff8111610bda576102f694610b6f913691016115c1565b939092610b7c8351612054565b6020840151828501519083519260208401947f939c21a48a8dbe3a9a2404a1d46691e4d39f6583d6ec6b35714604c986d801068652840152336060840152608083015260a082015260a08152610bd18161141b565b51902091611c25565b8580fd5b509134610336576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610c186114a0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc360160c08112610332576080855191610c51836113e3565b1261033257845190610c6282611398565b73ffffffffffffffffffffffffffffffffffffffff91602435838116810361049f578152604435838116810361049f57602082015265ffffffffffff606435818116810361032a5788830152608435908116810361049f576060820152815260a435938285168503610bda576020820194855260c4359087830182815260e43567ffffffffffffffff811161032657610cfe90369084016115c1565b929093804211610d88575050918591610d786102f6999a610d7e95610d238851611fbe565b90898c511690519083519260208401947ff3841cd1ff0085026a6327b620b67997ce40f282c88a8e905a7a5626e310f3d086528401526060830152608082015260808152610d70816113ff565b519020611bd9565b916120c7565b519251169161199d565b602492508a51917fcd21db4f000000000000000000000000000000000000000000000000000000008352820152fd5b5091346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc93818536011261033257610df36114a0565b9260249081359267ffffffffffffffff9788851161032a578590853603011261049f578051978589018981108282111761104a578252848301358181116103265785019036602383011215610326578382013591610e50836115ef565b90610e5d85519283611437565b838252602093878584019160071b83010191368311611046578801905b828210610fe9575050508a526044610e93868801611509565b96838c01978852013594838b0191868352604435908111610fe557610ebb90369087016115c1565b959096804211610fba575050508998995151610ed681611ebb565b908b5b818110610f9757505092889492610d7892610f6497958351610f02816103f98682018095611f66565b5190209073ffffffffffffffffffffffffffffffffffffffff9a8b8b51169151928551948501957faf1b0d30d2cab0380e68f0689007e3254993c596f2fdd0aaa7f4d04f794408638752850152830152608082015260808152610d70816113ff565b51169082515192845b848110610f78578580f35b80610f918585610f8b600195875161175e565b5161199d565b01610f6d565b80610311610fac8e9f9e93610fb2945161175e565b51611fbe565b9b9a9b610ed9565b8551917fcd21db4f000000000000000000000000000000000000000000000000000000008352820152fd5b8a80fd5b6080823603126110465785608091885161100281611398565b61100b85611509565b8152611018838601611509565b838201526110278a8601611607565b8a8201528d611037818701611607565b90820152815201910190610e7a565b8c80fd5b84896041867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5082346105bf576101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf576110b03661152a565b91807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c360112610332576110e2611478565b67ffffffffffffffff93906101043585811161049f5761110590369086016115c1565b90936101243596871161032a57611125610bd1966102f6983691016115c1565b969095825190611134826113ff565b606482527f5065726d69745769746e6573735472616e7366657246726f6d28546f6b656e5060208301527f65726d697373696f6e73207065726d69747465642c6164647265737320737065848301527f6e6465722c75696e74323536206e6f6e63652c75696e7432353620646561646c60608301527f696e652c0000000000000000000000000000000000000000000000000000000060808301528351948591816111e3602085018096611f93565b918237018b8152039361121c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868101835282611437565b5190209261122a8651612054565b6020878101518589015195519182019687526040820192909252336060820152608081019190915260a081019390935260e43560c08401528260e081016102e1565b5082346105bf576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033257813567ffffffffffffffff92838211610bda5736602383011215610bda5781013592831161032e576024906007368386831b8401011161049f57865b8581106112e5578780f35b80821b83019060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc83360301126103265761139288876001946060835161132c81611398565b611368608461133c8d8601611509565b9485845261134c60448201611509565b809785015261135d60648201611509565b809885015201611509565b918291015273ffffffffffffffffffffffffffffffffffffffff80808093169516931691166117a1565b016112da565b6080810190811067ffffffffffffffff8211176113b457604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff8211176113b457604052565b60a0810190811067ffffffffffffffff8211176113b457604052565b60c0810190811067ffffffffffffffff8211176113b457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176113b457604052565b60c4359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b600080fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc01906080821261149b576040805190611563826113e3565b8082941261149b57805181810181811067ffffffffffffffff8211176113b457825260043573ffffffffffffffffffffffffffffffffffffffff8116810361149b578152602435602082015282526044356020830152606435910152565b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020838186019501011161149b57565b67ffffffffffffffff81116113b45760051b60200190565b359065ffffffffffff8216820361149b57565b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020808501948460061b01011161149b57565b91909160608184031261149b576040805191611666836113e3565b8294813567ffffffffffffffff9081811161149b57830182601f8201121561149b578035611693816115ef565b926116a087519485611437565b818452602094858086019360061b8501019381851161149b579086899897969594939201925b8484106116e3575050505050855280820135908501520135910152565b90919293949596978483031261149b578851908982019082821085831117611730578a928992845261171487611509565b81528287013583820152815201930191908897969594936116c6565b602460007f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b80518210156117725760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b92919273ffffffffffffffffffffffffffffffffffffffff604060008284168152600160205282828220961695868252602052818120338252602052209485549565ffffffffffff8760a01c16804211611884575082871696838803611812575b5050611810955016926118b5565b565b878484161160001461184f57602488604051907ff96fb0710000000000000000000000000000000000000000000000000000000082526004820152fd5b7fffffffffffffffffffffffff000000000000000000000000000000000000000084846118109a031691161790553880611802565b602490604051907fd81b2f2e0000000000000000000000000000000000000000000000000000000082526004820152fd5b9060006064926020958295604051947f23b872dd0000000000000000000000000000000000000000000000000000000086526004860152602485015260448401525af13d15601f3d116001600051141617161561190e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b91908110156117725760061b0190565b3573ffffffffffffffffffffffffffffffffffffffff8116810361149b5790565b9065ffffffffffff908160608401511673ffffffffffffffffffffffffffffffffffffffff908185511694826020820151169280866040809401511695169560009187835260016020528383208984526020528383209916988983526020528282209184835460d01c03611af5579185611ace94927fc6a377bfc4eb120024a8ac08eef205be16b817020812c73223e81d1bdb9708ec98979694508715600014611ad35779ffffffffffff00000000000000000000000000000000000000009042165b60a01b167fffffffffffff00000000000000000000000000000000000000000000000000006001860160d01b1617179055519384938491604091949373ffffffffffffffffffffffffffffffffffffffff606085019616845265ffffffffffff809216602085015216910152565b0390a4565b5079ffffffffffff000000000000000000000000000000000000000087611a60565b600484517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b467f000000000000000000000000000000000000000000000000000000000000000003611b69577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86682527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a604082015246606082015230608082015260808152611bd3816113ff565b51902090565b611be1611b1e565b906040519060208201927f190100000000000000000000000000000000000000000000000000000000000084526022830152604282015260428152611bd381611398565b9192909360a435936040840151804211611cc65750602084510151808611611c955750918591610d78611c6594611c60602088015186611e47565b611bd9565b73ffffffffffffffffffffffffffffffffffffffff809151511692608435918216820361149b57611810936118b5565b602490604051907f3728b83d0000000000000000000000000000000000000000000000000000000082526004820152fd5b602490604051907fcd21db4f0000000000000000000000000000000000000000000000000000000082526004820152fd5b959093958051519560409283830151804211611e175750848803611dee57611d2e918691610d7860209b611c608d88015186611e47565b60005b868110611d42575050505050505050565b611d4d81835161175e565b5188611d5a83878a61196c565b01359089810151808311611dbe575091818888886001968596611d84575b50505050505001611d31565b611db395611dad9273ffffffffffffffffffffffffffffffffffffffff6105159351169561196c565b916118b5565b803888888883611d78565b6024908651907f3728b83d0000000000000000000000000000000000000000000000000000000082526004820152fd5b600484517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b6024908551907fcd21db4f0000000000000000000000000000000000000000000000000000000082526004820152fd5b9073ffffffffffffffffffffffffffffffffffffffff600160ff83161b9216600052600060205260406000209060081c6000526020526040600020818154188091551615611e9157565b60046040517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b90611ec5826115ef565b611ed26040519182611437565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0611f0082946115ef565b0190602036910137565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611f375760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b805160208092019160005b828110611f7f575050505090565b835185529381019392810192600101611f71565b9081519160005b838110611fab575050016000815290565b8060208092840101518185015201611f9a565b60405160208101917f65626cad6cb96493bf6f5ebea28756c966f023ab9e8a83a7101849d5573b3678835273ffffffffffffffffffffffffffffffffffffffff8082511660408401526020820151166060830152606065ffffffffffff9182604082015116608085015201511660a082015260a0815260c0810181811067ffffffffffffffff8211176113b45760405251902090565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a1845273ffffffffffffffffffffffffffffffffffffffff81511660408401520151606082015260608152611bd381611398565b919082604091031261149b576020823592013590565b6000843b61222e5750604182036121ac576120e4828201826120b1565b939092604010156117725760209360009360ff6040608095013560f81c5b60405194855216868401526040830152606082015282805260015afa156121a05773ffffffffffffffffffffffffffffffffffffffff806000511691821561217657160361214c57565b60046040517f815e1d64000000000000000000000000000000000000000000000000000000008152fd5b60046040517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b6040513d6000823e3d90fd5b60408203612204576121c0918101906120b1565b91601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84169360ff1c019060ff8211611f375760209360009360ff608094612102565b60046040517f4be6321b000000000000000000000000000000000000000000000000000000008152fd5b929391601f928173ffffffffffffffffffffffffffffffffffffffff60646020957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0604051988997889687947f1626ba7e000000000000000000000000000000000000000000000000000000009e8f8752600487015260406024870152816044870152868601378b85828601015201168101030192165afa9081156123a857829161232a575b507fffffffff000000000000000000000000000000000000000000000000000000009150160361230057565b60046040517fb0669cbc000000000000000000000000000000000000000000000000000000008152fd5b90506020813d82116123a0575b8161234460209383611437565b810103126103365751907fffffffff0000000000000000000000000000000000000000000000000000000082168203610a9a57507fffffffff0000000000000000000000000000000000000000000000000000000090386122d4565b3d9150612337565b6040513d84823e3d90fdfea164736f6c6343000811000a"); +/// `Permit2` creation bytecode (initcode) compiled from Uniswap/permit2 (commit cc56ad0) +/// with solc 0.8.17 (via-ir, optimizer `1_000_000` runs, `bytecode_hash="none"`). +/// No constructor arguments needed. +/// Regenerate with: `cd contracts/lib/permit2 && forge inspect Permit2 bytecode` +pub(crate) const PERMIT2_INITCODE: &[u8] = &hex!("60c0346100bb574660a052602081017f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a60408301524660608301523060808301526080825260a082019180831060018060401b038411176100a557826040525190206080526123c090816100c1823960805181611b47015260a05181611b210152f35b634e487b7160e01b600052604160045260246000fd5b600080fdfe6040608081526004908136101561001557600080fd5b600090813560e01c80630d58b1db1461126c578063137c29fe146110755780632a2d80d114610db75780632b67b57014610bde57806330f28b7a14610ade5780633644e51514610a9d57806336c7851614610a285780633ff9dcb1146109a85780634fe02b441461093f57806365d9723c146107ac57806387517c451461067a578063927da105146105c3578063cc53287f146104a3578063edd9444b1461033a5763fe8ec1a7146100c657600080fd5b346103365760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365767ffffffffffffffff833581811161033257610114903690860161164b565b60243582811161032e5761012b903690870161161a565b6101336114e6565b9160843585811161032a5761014b9036908a016115c1565b98909560a43590811161032657610164913691016115c1565b969095815190610173826113ff565b606b82527f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208301527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c61646472838301527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608301527f3620646561646c696e652c000000000000000000000000000000000000000000608083015282519a8b9181610222602085018096611f93565b918237018a8152039961025b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09b8c8101835282611437565b5190209085515161026b81611ebb565b908a5b8181106102f95750506102f6999a6102ed9183516102a081610294602082018095611f66565b03848101835282611437565b519020602089810151858b015195519182019687526040820192909252336060820152608081019190915260a081019390935260643560c08401528260e081015b03908101835282611437565b51902093611cf7565b80f35b8061031161030b610321938c5161175e565b51612054565b61031b828661175e565b52611f0a565b61026e565b8880fd5b8780fd5b8480fd5b8380fd5b5080fd5b5091346103365760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365767ffffffffffffffff9080358281116103325761038b903690830161164b565b60243583811161032e576103a2903690840161161a565b9390926103ad6114e6565b9160643590811161049f576103c4913691016115c1565b949093835151976103d489611ebb565b98885b81811061047d5750506102f697988151610425816103f9602082018095611f66565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611437565b5190206020860151828701519083519260208401947ffcf35f5ac6a2c28868dc44c302166470266239195f02b0ee408334829333b7668652840152336060840152608083015260a082015260a081526102ed8161141b565b808b61031b8261049461030b61049a968d5161175e565b9261175e565b6103d7565b8680fd5b5082346105bf57602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103325780359067ffffffffffffffff821161032e576104f49136910161161a565b929091845b848110610504578580f35b8061051a610515600193888861196c565b61197c565b61052f84610529848a8a61196c565b0161197c565b3389528385528589209173ffffffffffffffffffffffffffffffffffffffff80911692838b528652868a20911690818a5285528589207fffffffffffffffffffffffff000000000000000000000000000000000000000081541690558551918252848201527f89b1add15eff56b3dfe299ad94e01f2b52fbcb80ae1a3baea6ae8c04cb2b98a4853392a2016104f9565b8280fd5b50346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610676816105ff6114a0565b936106086114c3565b6106106114e6565b73ffffffffffffffffffffffffffffffffffffffff968716835260016020908152848420928816845291825283832090871683528152919020549251938316845260a083901c65ffffffffffff169084015260d09190911c604083015281906060820190565b0390f35b50346103365760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576106b26114a0565b906106bb6114c3565b916106c46114e6565b65ffffffffffff926064358481169081810361032a5779ffffffffffff0000000000000000000000000000000000000000947fda9fa7c1b00402c17d0161b249b1ab8bbec047c5a52207b9c112deffd817036b94338a5260016020527fffffffffffff0000000000000000000000000000000000000000000000000000858b209873ffffffffffffffffffffffffffffffffffffffff809416998a8d5260205283878d209b169a8b8d52602052868c209486156000146107a457504216925b8454921697889360a01b16911617179055815193845260208401523392a480f35b905092610783565b5082346105bf5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf576107e56114a0565b906107ee6114c3565b9265ffffffffffff604435818116939084810361032a57338852602091600183528489209673ffffffffffffffffffffffffffffffffffffffff80911697888b528452858a20981697888a5283528489205460d01c93848711156109175761ffff9085840316116108f05750907f55eb90d810e1700b35a8e7e25395ff7f2b2259abd7415ca2284dfb1c246418f393929133895260018252838920878a528252838920888a5282528389209079ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffff000000000000000000000000000000000000000000000000000083549260d01b16911617905582519485528401523392a480f35b84517f24d35a26000000000000000000000000000000000000000000000000000000008152fd5b5084517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b503461033657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336578060209273ffffffffffffffffffffffffffffffffffffffff61098f6114a0565b1681528084528181206024358252845220549051908152f35b5082346105bf57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf577f3704902f963766a4e561bbaab6e6cdc1b1dd12f6e9e99648da8843b3f46b918d90359160243533855284602052818520848652602052818520818154179055815193845260208401523392a280f35b8234610a9a5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610a9a57610a606114a0565b610a686114c3565b610a706114e6565b6064359173ffffffffffffffffffffffffffffffffffffffff8316830361032e576102f6936117a1565b80fd5b503461033657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602090610ad7611b1e565b9051908152f35b508290346105bf576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf57610b1a3661152a565b90807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c36011261033257610b4c611478565b9160e43567ffffffffffffffff8111610bda576102f694610b6f913691016115c1565b939092610b7c8351612054565b6020840151828501519083519260208401947f939c21a48a8dbe3a9a2404a1d46691e4d39f6583d6ec6b35714604c986d801068652840152336060840152608083015260a082015260a08152610bd18161141b565b51902091611c25565b8580fd5b509134610336576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610c186114a0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc360160c08112610332576080855191610c51836113e3565b1261033257845190610c6282611398565b73ffffffffffffffffffffffffffffffffffffffff91602435838116810361049f578152604435838116810361049f57602082015265ffffffffffff606435818116810361032a5788830152608435908116810361049f576060820152815260a435938285168503610bda576020820194855260c4359087830182815260e43567ffffffffffffffff811161032657610cfe90369084016115c1565b929093804211610d88575050918591610d786102f6999a610d7e95610d238851611fbe565b90898c511690519083519260208401947ff3841cd1ff0085026a6327b620b67997ce40f282c88a8e905a7a5626e310f3d086528401526060830152608082015260808152610d70816113ff565b519020611bd9565b916120c7565b519251169161199d565b602492508a51917fcd21db4f000000000000000000000000000000000000000000000000000000008352820152fd5b5091346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc93818536011261033257610df36114a0565b9260249081359267ffffffffffffffff9788851161032a578590853603011261049f578051978589018981108282111761104a578252848301358181116103265785019036602383011215610326578382013591610e50836115ef565b90610e5d85519283611437565b838252602093878584019160071b83010191368311611046578801905b828210610fe9575050508a526044610e93868801611509565b96838c01978852013594838b0191868352604435908111610fe557610ebb90369087016115c1565b959096804211610fba575050508998995151610ed681611ebb565b908b5b818110610f9757505092889492610d7892610f6497958351610f02816103f98682018095611f66565b5190209073ffffffffffffffffffffffffffffffffffffffff9a8b8b51169151928551948501957faf1b0d30d2cab0380e68f0689007e3254993c596f2fdd0aaa7f4d04f794408638752850152830152608082015260808152610d70816113ff565b51169082515192845b848110610f78578580f35b80610f918585610f8b600195875161175e565b5161199d565b01610f6d565b80610311610fac8e9f9e93610fb2945161175e565b51611fbe565b9b9a9b610ed9565b8551917fcd21db4f000000000000000000000000000000000000000000000000000000008352820152fd5b8a80fd5b6080823603126110465785608091885161100281611398565b61100b85611509565b8152611018838601611509565b838201526110278a8601611607565b8a8201528d611037818701611607565b90820152815201910190610e7a565b8c80fd5b84896041867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5082346105bf576101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf576110b03661152a565b91807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c360112610332576110e2611478565b67ffffffffffffffff93906101043585811161049f5761110590369086016115c1565b90936101243596871161032a57611125610bd1966102f6983691016115c1565b969095825190611134826113ff565b606482527f5065726d69745769746e6573735472616e7366657246726f6d28546f6b656e5060208301527f65726d697373696f6e73207065726d69747465642c6164647265737320737065848301527f6e6465722c75696e74323536206e6f6e63652c75696e7432353620646561646c60608301527f696e652c0000000000000000000000000000000000000000000000000000000060808301528351948591816111e3602085018096611f93565b918237018b8152039361121c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868101835282611437565b5190209261122a8651612054565b6020878101518589015195519182019687526040820192909252336060820152608081019190915260a081019390935260e43560c08401528260e081016102e1565b5082346105bf576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033257813567ffffffffffffffff92838211610bda5736602383011215610bda5781013592831161032e576024906007368386831b8401011161049f57865b8581106112e5578780f35b80821b83019060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc83360301126103265761139288876001946060835161132c81611398565b611368608461133c8d8601611509565b9485845261134c60448201611509565b809785015261135d60648201611509565b809885015201611509565b918291015273ffffffffffffffffffffffffffffffffffffffff80808093169516931691166117a1565b016112da565b6080810190811067ffffffffffffffff8211176113b457604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff8211176113b457604052565b60a0810190811067ffffffffffffffff8211176113b457604052565b60c0810190811067ffffffffffffffff8211176113b457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176113b457604052565b60c4359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b600080fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc01906080821261149b576040805190611563826113e3565b8082941261149b57805181810181811067ffffffffffffffff8211176113b457825260043573ffffffffffffffffffffffffffffffffffffffff8116810361149b578152602435602082015282526044356020830152606435910152565b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020838186019501011161149b57565b67ffffffffffffffff81116113b45760051b60200190565b359065ffffffffffff8216820361149b57565b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020808501948460061b01011161149b57565b91909160608184031261149b576040805191611666836113e3565b8294813567ffffffffffffffff9081811161149b57830182601f8201121561149b578035611693816115ef565b926116a087519485611437565b818452602094858086019360061b8501019381851161149b579086899897969594939201925b8484106116e3575050505050855280820135908501520135910152565b90919293949596978483031261149b578851908982019082821085831117611730578a928992845261171487611509565b81528287013583820152815201930191908897969594936116c6565b602460007f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b80518210156117725760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b92919273ffffffffffffffffffffffffffffffffffffffff604060008284168152600160205282828220961695868252602052818120338252602052209485549565ffffffffffff8760a01c16804211611884575082871696838803611812575b5050611810955016926118b5565b565b878484161160001461184f57602488604051907ff96fb0710000000000000000000000000000000000000000000000000000000082526004820152fd5b7fffffffffffffffffffffffff000000000000000000000000000000000000000084846118109a031691161790553880611802565b602490604051907fd81b2f2e0000000000000000000000000000000000000000000000000000000082526004820152fd5b9060006064926020958295604051947f23b872dd0000000000000000000000000000000000000000000000000000000086526004860152602485015260448401525af13d15601f3d116001600051141617161561190e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b91908110156117725760061b0190565b3573ffffffffffffffffffffffffffffffffffffffff8116810361149b5790565b9065ffffffffffff908160608401511673ffffffffffffffffffffffffffffffffffffffff908185511694826020820151169280866040809401511695169560009187835260016020528383208984526020528383209916988983526020528282209184835460d01c03611af5579185611ace94927fc6a377bfc4eb120024a8ac08eef205be16b817020812c73223e81d1bdb9708ec98979694508715600014611ad35779ffffffffffff00000000000000000000000000000000000000009042165b60a01b167fffffffffffff00000000000000000000000000000000000000000000000000006001860160d01b1617179055519384938491604091949373ffffffffffffffffffffffffffffffffffffffff606085019616845265ffffffffffff809216602085015216910152565b0390a4565b5079ffffffffffff000000000000000000000000000000000000000087611a60565b600484517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b467f000000000000000000000000000000000000000000000000000000000000000003611b69577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86682527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a604082015246606082015230608082015260808152611bd3816113ff565b51902090565b611be1611b1e565b906040519060208201927f190100000000000000000000000000000000000000000000000000000000000084526022830152604282015260428152611bd381611398565b9192909360a435936040840151804211611cc65750602084510151808611611c955750918591610d78611c6594611c60602088015186611e47565b611bd9565b73ffffffffffffffffffffffffffffffffffffffff809151511692608435918216820361149b57611810936118b5565b602490604051907f3728b83d0000000000000000000000000000000000000000000000000000000082526004820152fd5b602490604051907fcd21db4f0000000000000000000000000000000000000000000000000000000082526004820152fd5b959093958051519560409283830151804211611e175750848803611dee57611d2e918691610d7860209b611c608d88015186611e47565b60005b868110611d42575050505050505050565b611d4d81835161175e565b5188611d5a83878a61196c565b01359089810151808311611dbe575091818888886001968596611d84575b50505050505001611d31565b611db395611dad9273ffffffffffffffffffffffffffffffffffffffff6105159351169561196c565b916118b5565b803888888883611d78565b6024908651907f3728b83d0000000000000000000000000000000000000000000000000000000082526004820152fd5b600484517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b6024908551907fcd21db4f0000000000000000000000000000000000000000000000000000000082526004820152fd5b9073ffffffffffffffffffffffffffffffffffffffff600160ff83161b9216600052600060205260406000209060081c6000526020526040600020818154188091551615611e9157565b60046040517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b90611ec5826115ef565b611ed26040519182611437565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0611f0082946115ef565b0190602036910137565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611f375760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b805160208092019160005b828110611f7f575050505090565b835185529381019392810192600101611f71565b9081519160005b838110611fab575050016000815290565b8060208092840101518185015201611f9a565b60405160208101917f65626cad6cb96493bf6f5ebea28756c966f023ab9e8a83a7101849d5573b3678835273ffffffffffffffffffffffffffffffffffffffff8082511660408401526020820151166060830152606065ffffffffffff9182604082015116608085015201511660a082015260a0815260c0810181811067ffffffffffffffff8211176113b45760405251902090565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a1845273ffffffffffffffffffffffffffffffffffffffff81511660408401520151606082015260608152611bd381611398565b919082604091031261149b576020823592013590565b6000843b61222e5750604182036121ac576120e4828201826120b1565b939092604010156117725760209360009360ff6040608095013560f81c5b60405194855216868401526040830152606082015282805260015afa156121a05773ffffffffffffffffffffffffffffffffffffffff806000511691821561217657160361214c57565b60046040517f815e1d64000000000000000000000000000000000000000000000000000000008152fd5b60046040517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b6040513d6000823e3d90fd5b60408203612204576121c0918101906120b1565b91601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84169360ff1c019060ff8211611f375760209360009360ff608094612102565b60046040517f4be6321b000000000000000000000000000000000000000000000000000000008152fd5b929391601f928173ffffffffffffffffffffffffffffffffffffffff60646020957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0604051988997889687947f1626ba7e000000000000000000000000000000000000000000000000000000009e8f8752600487015260406024870152816044870152868601378b85828601015201168101030192165afa9081156123a857829161232a575b507fffffffff000000000000000000000000000000000000000000000000000000009150160361230057565b60046040517fb0669cbc000000000000000000000000000000000000000000000000000000008152fd5b90506020813d82116123a0575b8161234460209383611437565b810103126103365751907fffffffff0000000000000000000000000000000000000000000000000000000082168203610a9a57507fffffffff0000000000000000000000000000000000000000000000000000000090386122d4565b3d9150612337565b6040513d84823e3d90fdfea164736f6c6343000811000a"); + // ── Immutable reference offsets (from compiled artifact `immutableReferences`) ── /// `_CACHED_CHAIN_ID` (uint256) — from `EIP712.sol`. From 1f7e2ccf8515ad5b590c7d74f91ae3e5de374e5a Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 17:18:23 +0200 Subject: [PATCH 03/18] feat(ev-deployer): add CREATE2 address computation module --- bin/ev-deployer/src/deploy/create2.rs | 74 +++++++++++++++++++++++++++ bin/ev-deployer/src/deploy/mod.rs | 1 + bin/ev-deployer/src/main.rs | 1 + 3 files changed, 76 insertions(+) create mode 100644 bin/ev-deployer/src/deploy/create2.rs create mode 100644 bin/ev-deployer/src/deploy/mod.rs diff --git a/bin/ev-deployer/src/deploy/create2.rs b/bin/ev-deployer/src/deploy/create2.rs new file mode 100644 index 0000000..b1d8deb --- /dev/null +++ b/bin/ev-deployer/src/deploy/create2.rs @@ -0,0 +1,74 @@ +//! CREATE2 address computation. + +use alloy_primitives::{Address, Bytes, B256, keccak256}; + +/// The deterministic deployer factory address (Nick's factory). +/// See: https://github.com/Arachnid/deterministic-deployment-proxy +pub(crate) const DETERMINISTIC_DEPLOYER: Address = + Address::new(alloy_primitives::hex!("4e59b44847b379578588920ca78fbf26c0b4956c")); + +/// Compute the CREATE2 address for a contract deployed via the deterministic deployer. +/// +/// The factory expects calldata `salt ++ initcode` and deploys via: +/// `CREATE2(value=0, offset, size, salt)` +/// +/// The resulting address is: +/// `keccak256(0xff ++ factory ++ salt ++ keccak256(initcode))[12..]` +pub(crate) fn compute_address(salt: B256, initcode: &[u8]) -> Address { + let init_code_hash = keccak256(initcode); + DETERMINISTIC_DEPLOYER.create2(salt, init_code_hash) +} + +/// Build the calldata to send to the deterministic deployer factory. +/// Format: `salt (32 bytes) ++ initcode` +pub(crate) fn build_factory_calldata(salt: B256, initcode: &[u8]) -> Bytes { + let mut data = Vec::with_capacity(32 + initcode.len()); + data.extend_from_slice(salt.as_slice()); + data.extend_from_slice(initcode); + Bytes::from(data) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::hex; + + #[test] + fn known_create2_address() { + let salt = B256::ZERO; + // Minimal initcode: PUSH1 0x00 PUSH1 0x00 RETURN (returns empty code) + let initcode = hex!("60006000f3"); + let addr = compute_address(salt, &initcode); + + let init_hash = keccak256(&initcode); + let expected = DETERMINISTIC_DEPLOYER.create2(salt, init_hash); + assert_eq!(addr, expected); + } + + #[test] + fn different_salts_different_addresses() { + let initcode = hex!("60006000f3"); + let addr1 = compute_address(B256::ZERO, &initcode); + let addr2 = compute_address(B256::with_last_byte(1), &initcode); + assert_ne!(addr1, addr2); + } + + #[test] + fn different_initcode_different_addresses() { + let salt = B256::ZERO; + let addr1 = compute_address(salt, &hex!("60006000f3")); + let addr2 = compute_address(salt, &hex!("60016000f3")); + assert_ne!(addr1, addr2); + } + + #[test] + fn factory_calldata_format() { + let salt = B256::with_last_byte(0x42); + let initcode = hex!("aabbcc"); + let calldata = build_factory_calldata(salt, &initcode); + + assert_eq!(calldata.len(), 32 + 3); + assert_eq!(&calldata[..32], salt.as_slice()); + assert_eq!(&calldata[32..], &hex!("aabbcc")); + } +} diff --git a/bin/ev-deployer/src/deploy/mod.rs b/bin/ev-deployer/src/deploy/mod.rs new file mode 100644 index 0000000..c099f38 --- /dev/null +++ b/bin/ev-deployer/src/deploy/mod.rs @@ -0,0 +1 @@ +pub(crate) mod create2; diff --git a/bin/ev-deployer/src/main.rs b/bin/ev-deployer/src/main.rs index 8ad8d7d..57ec437 100644 --- a/bin/ev-deployer/src/main.rs +++ b/bin/ev-deployer/src/main.rs @@ -2,6 +2,7 @@ mod config; mod contracts; +mod deploy; mod genesis; mod output; From 826c10d897974e9c714c13a035fa9c2e70bf69f3 Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 17:20:33 +0200 Subject: [PATCH 04/18] feat(ev-deployer): add deploy state file with immutability checks --- bin/ev-deployer/Cargo.toml | 1 + bin/ev-deployer/src/deploy/mod.rs | 1 + bin/ev-deployer/src/deploy/state.rs | 278 ++++++++++++++++++++++++++++ 3 files changed, 280 insertions(+) create mode 100644 bin/ev-deployer/src/deploy/state.rs diff --git a/bin/ev-deployer/Cargo.toml b/bin/ev-deployer/Cargo.toml index b80d21a..0b8d072 100644 --- a/bin/ev-deployer/Cargo.toml +++ b/bin/ev-deployer/Cargo.toml @@ -15,6 +15,7 @@ serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } toml = "0.8" eyre = { workspace = true } +rand = { workspace = true } [dev-dependencies] tempfile = { workspace = true } diff --git a/bin/ev-deployer/src/deploy/mod.rs b/bin/ev-deployer/src/deploy/mod.rs index c099f38..2aa1071 100644 --- a/bin/ev-deployer/src/deploy/mod.rs +++ b/bin/ev-deployer/src/deploy/mod.rs @@ -1 +1,2 @@ pub(crate) mod create2; +pub(crate) mod state; diff --git a/bin/ev-deployer/src/deploy/state.rs b/bin/ev-deployer/src/deploy/state.rs new file mode 100644 index 0000000..a3adefd --- /dev/null +++ b/bin/ev-deployer/src/deploy/state.rs @@ -0,0 +1,278 @@ +//! Deploy state file: tracks deployment progress with resumability. + +use crate::config::DeployConfig; +use alloy_primitives::{Address, B256}; +use rand::RngExt; +use serde::{Deserialize, Serialize}; +use std::path::Path; + +/// Current state file schema version. +const STATE_VERSION: u32 = 1; + +/// Overall deployment state, persisted to JSON. +#[derive(Debug, Serialize, Deserialize)] +pub(crate) struct DeployState { + /// Schema version. + pub version: u32, + /// Random salt for CREATE2 deployments. + pub create2_salt: B256, + /// Snapshot of the config at first run — used for immutability checks. + pub applied_intent: AppliedIntent, + /// Per-contract deployment state. + #[serde(default)] + pub contracts: ContractStates, +} + +/// Snapshot of the config that was used for the first deployment. +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub(crate) struct AppliedIntent { + pub chain_id: u64, + pub admin_proxy: Option, + pub permit2: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub(crate) struct AppliedAdminProxy { + pub owner: Address, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub(crate) struct AppliedPermit2 {} + +/// Per-contract deployment states. +#[derive(Debug, Default, Serialize, Deserialize)] +pub(crate) struct ContractStates { + pub admin_proxy: Option, + pub permit2: Option, +} + +/// State of a single contract deployment. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) struct ContractState { + pub status: ContractStatus, + pub address: Address, + #[serde(skip_serializing_if = "Option::is_none")] + pub deploy_tx: Option, +} + +/// Contract deployment status progression. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub(crate) enum ContractStatus { + Pending, + Deployed, + Verified, +} + +impl DeployState { + /// Create a new state from config, generating a random salt. + pub(crate) fn new(config: &DeployConfig) -> Self { + let mut salt_bytes = [0u8; 32]; + let mut rng = rand::rng(); + rng.fill(&mut salt_bytes); + let salt = B256::from(salt_bytes); + + Self { + version: STATE_VERSION, + create2_salt: salt, + applied_intent: AppliedIntent::from_config(config), + contracts: ContractStates::default(), + } + } + + /// Load state from a JSON file. + pub(crate) fn load(path: &Path) -> eyre::Result { + let content = std::fs::read_to_string(path)?; + let state: Self = serde_json::from_str(&content)?; + eyre::ensure!( + state.version == STATE_VERSION, + "unsupported state version: {} (expected {})", + state.version, + STATE_VERSION + ); + Ok(state) + } + + /// Save state to a JSON file. + pub(crate) fn save(&self, path: &Path) -> eyre::Result<()> { + let json = serde_json::to_string_pretty(self)?; + std::fs::write(path, json)?; + Ok(()) + } + + /// Validate that the current config is compatible with the applied intent. + /// Immutable fields cannot change. New contracts can be added. + pub(crate) fn validate_immutability(&self, config: &DeployConfig) -> eyre::Result<()> { + let current = &self.applied_intent; + + eyre::ensure!( + config.chain.chain_id == current.chain_id, + "immutability violation: chain_id changed from {} to {}", + current.chain_id, + config.chain.chain_id + ); + + // If admin_proxy was in the original intent, its owner must not change + if let Some(ref original_ap) = current.admin_proxy { + if let Some(ref new_ap) = config.contracts.admin_proxy { + eyre::ensure!( + new_ap.owner == original_ap.owner, + "immutability violation: admin_proxy.owner changed from {} to {}", + original_ap.owner, + new_ap.owner + ); + } else { + eyre::bail!("immutability violation: admin_proxy was configured but is now missing"); + } + } + + // If permit2 was in the original intent, it must still be present + if current.permit2.is_some() { + eyre::ensure!( + config.contracts.permit2.is_some(), + "immutability violation: permit2 was configured but is now missing" + ); + } + + Ok(()) + } +} + +impl AppliedIntent { + fn from_config(config: &DeployConfig) -> Self { + Self { + chain_id: config.chain.chain_id, + admin_proxy: config + .contracts + .admin_proxy + .as_ref() + .map(|ap| AppliedAdminProxy { owner: ap.owner }), + permit2: config + .contracts + .permit2 + .as_ref() + .map(|_| AppliedPermit2 {}), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::config::*; + use alloy_primitives::address; + + fn test_config() -> DeployConfig { + DeployConfig { + chain: ChainConfig { chain_id: 1234 }, + contracts: ContractsConfig { + admin_proxy: Some(AdminProxyConfig { + address: None, + owner: address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), + }), + permit2: Some(Permit2Config { address: None }), + }, + } + } + + #[test] + fn new_state_has_random_salt() { + let s1 = DeployState::new(&test_config()); + let s2 = DeployState::new(&test_config()); + assert_ne!(s1.create2_salt, s2.create2_salt); + } + + #[test] + fn new_state_snapshots_intent() { + let state = DeployState::new(&test_config()); + assert_eq!(state.applied_intent.chain_id, 1234); + assert!(state.applied_intent.admin_proxy.is_some()); + assert!(state.applied_intent.permit2.is_some()); + } + + #[test] + fn roundtrip_save_load() { + let state = DeployState::new(&test_config()); + let tmp = tempfile::NamedTempFile::new().unwrap(); + state.save(tmp.path()).unwrap(); + let loaded = DeployState::load(tmp.path()).unwrap(); + assert_eq!(loaded.create2_salt, state.create2_salt); + assert_eq!(loaded.applied_intent, state.applied_intent); + } + + #[test] + fn immutability_ok_same_config() { + let config = test_config(); + let state = DeployState::new(&config); + assert!(state.validate_immutability(&config).is_ok()); + } + + #[test] + fn immutability_rejects_chain_id_change() { + let config = test_config(); + let state = DeployState::new(&config); + let mut changed = config.clone(); + changed.chain.chain_id = 9999; + let err = state + .validate_immutability(&changed) + .unwrap_err() + .to_string(); + assert!(err.contains("chain_id changed"), "{err}"); + } + + #[test] + fn immutability_rejects_owner_change() { + let config = test_config(); + let state = DeployState::new(&config); + let mut changed = config.clone(); + changed.contracts.admin_proxy.as_mut().unwrap().owner = + address!("0000000000000000000000000000000000000001"); + let err = state + .validate_immutability(&changed) + .unwrap_err() + .to_string(); + assert!(err.contains("admin_proxy.owner changed"), "{err}"); + } + + #[test] + fn immutability_allows_adding_new_contract() { + let config = DeployConfig { + chain: ChainConfig { chain_id: 1234 }, + contracts: ContractsConfig { + admin_proxy: Some(AdminProxyConfig { + address: None, + owner: address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), + }), + permit2: None, + }, + }; + let state = DeployState::new(&config); + + // Now add permit2 — this should be allowed + let mut extended = config.clone(); + extended.contracts.permit2 = Some(Permit2Config { address: None }); + assert!(state.validate_immutability(&extended).is_ok()); + } + + #[test] + fn immutability_rejects_removing_contract() { + let config = test_config(); + let state = DeployState::new(&config); + let mut changed = config.clone(); + changed.contracts.admin_proxy = None; + let err = state + .validate_immutability(&changed) + .unwrap_err() + .to_string(); + assert!( + err.contains("admin_proxy was configured but is now missing"), + "{err}" + ); + } + + #[test] + fn contract_status_ordering() { + assert!(ContractStatus::Pending < ContractStatus::Deployed); + assert!(ContractStatus::Deployed < ContractStatus::Verified); + } +} From f9054b76ff1d115a0035353b5c496dc3bd0cb76e Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 17:23:41 +0200 Subject: [PATCH 05/18] feat(ev-deployer): add ChainDeployer trait and LiveDeployer --- bin/ev-deployer/Cargo.toml | 5 ++ bin/ev-deployer/src/deploy/deployer.rs | 79 ++++++++++++++++++++++++++ bin/ev-deployer/src/deploy/mod.rs | 1 + 3 files changed, 85 insertions(+) create mode 100644 bin/ev-deployer/src/deploy/deployer.rs diff --git a/bin/ev-deployer/Cargo.toml b/bin/ev-deployer/Cargo.toml index 0b8d072..ff9eae7 100644 --- a/bin/ev-deployer/Cargo.toml +++ b/bin/ev-deployer/Cargo.toml @@ -10,6 +10,11 @@ authors.workspace = true [dependencies] alloy-primitives = { workspace = true, features = ["serde"] } +alloy = { workspace = true } +alloy-rpc-types-eth = { workspace = true } +alloy-signer-local = { workspace = true } +async-trait = { workspace = true } +tokio = { workspace = true } clap = { workspace = true, features = ["derive", "env"] } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } diff --git a/bin/ev-deployer/src/deploy/deployer.rs b/bin/ev-deployer/src/deploy/deployer.rs new file mode 100644 index 0000000..8fa9571 --- /dev/null +++ b/bin/ev-deployer/src/deploy/deployer.rs @@ -0,0 +1,79 @@ +//! ChainDeployer trait and LiveDeployer implementation. + +use crate::deploy::create2::{build_factory_calldata, DETERMINISTIC_DEPLOYER}; +use alloy::network::EthereumWallet; +use alloy::providers::{Provider, ProviderBuilder}; +use alloy_primitives::{Address, Bytes, B256}; +use alloy_rpc_types_eth::TransactionRequest; +use alloy_signer_local::PrivateKeySigner; +use async_trait::async_trait; + +/// Receipt from a confirmed transaction. +#[derive(Debug)] +pub(crate) struct TxReceipt { + pub tx_hash: B256, + pub success: bool, +} + +/// Abstracts on-chain operations for the deploy pipeline. +#[async_trait] +pub(crate) trait ChainDeployer: Send + Sync { + /// Get the chain ID of the connected chain. + async fn chain_id(&self) -> eyre::Result; + + /// Read the bytecode at an address. Returns empty bytes if no code. + async fn get_code(&self, address: Address) -> eyre::Result; + + /// Send a CREATE2 deployment transaction via the deterministic deployer. + /// Returns the tx hash once the tx is confirmed. + async fn deploy_create2(&self, salt: B256, initcode: &[u8]) -> eyre::Result; +} + +/// Live deployer using alloy provider + signer. +pub(crate) struct LiveDeployer { + provider: Box, +} + +impl LiveDeployer { + /// Create a new LiveDeployer from an RPC URL and a hex-encoded private key. + pub(crate) fn new(rpc_url: &str, private_key_hex: &str) -> eyre::Result { + let key_hex = private_key_hex.strip_prefix("0x").unwrap_or(private_key_hex); + let signer: PrivateKeySigner = key_hex.parse()?; + let wallet = EthereumWallet::from(signer); + + let provider = ProviderBuilder::new() + .wallet(wallet) + .connect_http(rpc_url.parse()?); + + Ok(Self { + provider: Box::new(provider), + }) + } +} + +#[async_trait] +impl ChainDeployer for LiveDeployer { + async fn chain_id(&self) -> eyre::Result { + Ok(self.provider.get_chain_id().await?) + } + + async fn get_code(&self, address: Address) -> eyre::Result { + Ok(self.provider.get_code_at(address).await?) + } + + async fn deploy_create2(&self, salt: B256, initcode: &[u8]) -> eyre::Result { + let calldata = build_factory_calldata(salt, initcode); + + let tx = TransactionRequest::default() + .to(DETERMINISTIC_DEPLOYER) + .input(calldata.into()); + + let pending = self.provider.send_transaction(tx).await?; + let receipt = pending.get_receipt().await?; + + Ok(TxReceipt { + tx_hash: receipt.transaction_hash, + success: receipt.status(), + }) + } +} diff --git a/bin/ev-deployer/src/deploy/mod.rs b/bin/ev-deployer/src/deploy/mod.rs index 2aa1071..022531a 100644 --- a/bin/ev-deployer/src/deploy/mod.rs +++ b/bin/ev-deployer/src/deploy/mod.rs @@ -1,2 +1,3 @@ pub(crate) mod create2; +pub(crate) mod deployer; pub(crate) mod state; From 2b90e825a7bd0ac0423748d6da36123af85e369f Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 17:25:59 +0200 Subject: [PATCH 06/18] feat(ev-deployer): add deploy pipeline with mock-tested flow --- bin/ev-deployer/src/deploy/mod.rs | 1 + bin/ev-deployer/src/deploy/pipeline.rs | 471 +++++++++++++++++++++++++ 2 files changed, 472 insertions(+) create mode 100644 bin/ev-deployer/src/deploy/pipeline.rs diff --git a/bin/ev-deployer/src/deploy/mod.rs b/bin/ev-deployer/src/deploy/mod.rs index 022531a..7990f24 100644 --- a/bin/ev-deployer/src/deploy/mod.rs +++ b/bin/ev-deployer/src/deploy/mod.rs @@ -1,3 +1,4 @@ pub(crate) mod create2; pub(crate) mod deployer; +pub(crate) mod pipeline; pub(crate) mod state; diff --git a/bin/ev-deployer/src/deploy/pipeline.rs b/bin/ev-deployer/src/deploy/pipeline.rs new file mode 100644 index 0000000..5dbf5b0 --- /dev/null +++ b/bin/ev-deployer/src/deploy/pipeline.rs @@ -0,0 +1,471 @@ +//! Deploy pipeline: orchestrates the full deployment flow. + +use crate::config::DeployConfig; +use crate::contracts; +use crate::deploy::create2::{compute_address, DETERMINISTIC_DEPLOYER}; +use crate::deploy::deployer::ChainDeployer; +use crate::deploy::state::{ContractState, ContractStatus, DeployState}; +use alloy_primitives::{Address, B256}; +use std::path::{Path, PathBuf}; + +/// Configuration for the deploy pipeline. +pub(crate) struct PipelineConfig { + pub config: DeployConfig, + pub state_path: PathBuf, + pub addresses_out: Option, +} + +/// Run the full deploy pipeline. +pub(crate) async fn run( + pipeline_cfg: &PipelineConfig, + deployer: &dyn ChainDeployer, +) -> eyre::Result<()> { + // ── Step 1: Init ── + eprintln!("[1/5] Connecting to RPC..."); + let chain_id = deployer.chain_id().await?; + eprintln!(" chain_id={chain_id}"); + + eyre::ensure!( + chain_id == pipeline_cfg.config.chain.chain_id, + "chain_id mismatch: config says {}, RPC reports {}", + pipeline_cfg.config.chain.chain_id, + chain_id + ); + + eprintln!("[2/5] Verifying deterministic deployer..."); + let deployer_code = deployer.get_code(DETERMINISTIC_DEPLOYER).await?; + eyre::ensure!( + !deployer_code.is_empty(), + "deterministic deployer not found at {} -- deploy it before running ev-deployer deploy", + DETERMINISTIC_DEPLOYER + ); + eprintln!(" OK"); + + // Load or create state + let mut state = if pipeline_cfg.state_path.exists() { + let state = DeployState::load(&pipeline_cfg.state_path)?; + state.validate_immutability(&pipeline_cfg.config)?; + state + } else { + let state = DeployState::new(&pipeline_cfg.config); + state.save(&pipeline_cfg.state_path)?; + state + }; + + let salt = state.create2_salt; + + // ── Step 2: Deploy AdminProxy ── + if let Some(ref ap_config) = pipeline_cfg.config.contracts.admin_proxy { + eprintln!("[3/5] Deploying AdminProxy..."); + + if ap_config.address.is_some() { + eprintln!(" WARN: contracts.admin_proxy.address is ignored in deploy mode"); + } + + let initcode = build_admin_proxy_initcode(ap_config.owner); + let address = compute_address(salt, &initcode); + + deploy_contract( + deployer, + &mut state, + "admin_proxy", + address, + salt, + &initcode, + contracts::admin_proxy::ADMIN_PROXY_BYTECODE, + &pipeline_cfg.state_path, + ) + .await?; + } else { + eprintln!("[3/5] AdminProxy not configured, skipping"); + } + + // ── Step 3: Deploy Permit2 ── + if pipeline_cfg.config.contracts.permit2.is_some() { + eprintln!("[4/5] Deploying Permit2..."); + + if pipeline_cfg + .config + .contracts + .permit2 + .as_ref() + .unwrap() + .address + .is_some() + { + eprintln!(" WARN: contracts.permit2.address is ignored in deploy mode"); + } + + let initcode = contracts::permit2::PERMIT2_INITCODE.to_vec(); + let address = compute_address(salt, &initcode); + + let expected_runtime = + contracts::permit2::expected_runtime_bytecode(chain_id, address); + + deploy_contract( + deployer, + &mut state, + "permit2", + address, + salt, + &initcode, + &expected_runtime, + &pipeline_cfg.state_path, + ) + .await?; + } else { + eprintln!("[4/5] Permit2 not configured, skipping"); + } + + // ── Step 4: Verify ── + eprintln!("[5/5] Verifying bytecodes..."); + verify_all(deployer, &mut state, &pipeline_cfg.config, chain_id).await?; + state.save(&pipeline_cfg.state_path)?; + eprintln!(" OK"); + + // ── Step 5: Output ── + eprintln!(); + eprintln!( + "Deploy complete. State saved to {}", + pipeline_cfg.state_path.display() + ); + + if let Some(ref addr_path) = pipeline_cfg.addresses_out { + let manifest = build_deploy_manifest(&state); + let json = serde_json::to_string_pretty(&manifest)?; + std::fs::write(addr_path, &json)?; + eprintln!("Wrote address manifest to {}", addr_path.display()); + } + + Ok(()) +} + +/// Build AdminProxy initcode with constructor argument. +fn build_admin_proxy_initcode(owner: Address) -> Vec { + let mut initcode = contracts::admin_proxy::ADMIN_PROXY_INITCODE.to_vec(); + // ABI-encode the owner address as a 32-byte word and append + initcode.extend_from_slice(owner.into_word().as_slice()); + initcode +} + +/// Deploy a single contract via CREATE2 with idempotency. +async fn deploy_contract( + deployer: &dyn ChainDeployer, + state: &mut DeployState, + name: &str, + address: Address, + salt: B256, + initcode: &[u8], + expected_runtime: &[u8], + state_path: &Path, +) -> eyre::Result<()> { + // Check if already deployed or verified in state + let current_status = get_contract_status(state, name); + if current_status >= Some(ContractStatus::Deployed) { + eprintln!(" already deployed at {address}, skipping"); + return Ok(()); + } + + // Idempotency: check if code already exists on-chain + let existing_code = deployer.get_code(address).await?; + if !existing_code.is_empty() { + if existing_code.as_ref() == expected_runtime { + eprintln!(" found matching bytecode at {address}, marking as deployed"); + set_contract_state( + state, + name, + ContractState { + status: ContractStatus::Deployed, + address, + deploy_tx: None, + }, + ); + state.save(state_path)?; + return Ok(()); + } else { + eyre::bail!( + "unexpected bytecode at {address}: expected {} bytes, found {} bytes", + expected_runtime.len(), + existing_code.len() + ); + } + } + + // Deploy + let receipt = deployer.deploy_create2(salt, initcode).await?; + eyre::ensure!( + receipt.success, + "CREATE2 deploy tx reverted for {name}: tx={}", + receipt.tx_hash + ); + + eprintln!(" tx={} address={address}", receipt.tx_hash); + + set_contract_state( + state, + name, + ContractState { + status: ContractStatus::Deployed, + address, + deploy_tx: Some(receipt.tx_hash), + }, + ); + state.save(state_path)?; + + Ok(()) +} + +/// Verify all deployed contracts have matching on-chain bytecode. +async fn verify_all( + deployer: &dyn ChainDeployer, + state: &mut DeployState, + _config: &DeployConfig, + chain_id: u64, +) -> eyre::Result<()> { + if let Some(ref cs) = state.contracts.admin_proxy { + if cs.status == ContractStatus::Deployed { + let on_chain = deployer.get_code(cs.address).await?; + let expected = contracts::admin_proxy::ADMIN_PROXY_BYTECODE; + eyre::ensure!( + on_chain.as_ref() == expected, + "bytecode mismatch at {}: expected {} bytes, got {} bytes", + cs.address, + expected.len(), + on_chain.len() + ); + let mut updated = cs.clone(); + updated.status = ContractStatus::Verified; + state.contracts.admin_proxy = Some(updated); + } + } + + if let Some(ref cs) = state.contracts.permit2 { + if cs.status == ContractStatus::Deployed { + let on_chain = deployer.get_code(cs.address).await?; + let expected = + contracts::permit2::expected_runtime_bytecode(chain_id, cs.address); + eyre::ensure!( + on_chain.as_ref() == expected.as_slice(), + "bytecode mismatch at {}: expected {} bytes, got {} bytes", + cs.address, + expected.len(), + on_chain.len() + ); + let mut updated = cs.clone(); + updated.status = ContractStatus::Verified; + state.contracts.permit2 = Some(updated); + } + } + + Ok(()) +} + +fn get_contract_status(state: &DeployState, name: &str) -> Option { + match name { + "admin_proxy" => state.contracts.admin_proxy.as_ref().map(|c| c.status), + "permit2" => state.contracts.permit2.as_ref().map(|c| c.status), + _ => None, + } +} + +fn set_contract_state(state: &mut DeployState, name: &str, cs: ContractState) { + match name { + "admin_proxy" => state.contracts.admin_proxy = Some(cs), + "permit2" => state.contracts.permit2 = Some(cs), + _ => {} + } +} + +fn build_deploy_manifest(state: &DeployState) -> serde_json::Value { + let mut manifest = serde_json::Map::new(); + if let Some(ref cs) = state.contracts.admin_proxy { + manifest.insert( + "admin_proxy".to_string(), + serde_json::Value::String(format!("{}", cs.address)), + ); + } + if let Some(ref cs) = state.contracts.permit2 { + manifest.insert( + "permit2".to_string(), + serde_json::Value::String(format!("{}", cs.address)), + ); + } + serde_json::Value::Object(manifest) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::config::*; + use crate::deploy::deployer::TxReceipt; + use alloy_primitives::{address, Bytes}; + use async_trait::async_trait; + use std::collections::HashMap; + use std::sync::Mutex; + + /// Mock deployer for testing the pipeline without a live chain. + struct MockDeployer { + chain_id: u64, + code: Mutex>, + deploys: Mutex)>>, + } + + impl MockDeployer { + fn new(chain_id: u64) -> Self { + let mut code = HashMap::new(); + code.insert(DETERMINISTIC_DEPLOYER, Bytes::from_static(&[0x01])); + Self { + chain_id, + code: Mutex::new(code), + deploys: Mutex::new(Vec::new()), + } + } + } + + #[async_trait] + impl ChainDeployer for MockDeployer { + async fn chain_id(&self) -> eyre::Result { + Ok(self.chain_id) + } + + async fn get_code(&self, address: Address) -> eyre::Result { + Ok(self + .code + .lock() + .unwrap() + .get(&address) + .cloned() + .unwrap_or_default()) + } + + async fn deploy_create2( + &self, + salt: B256, + initcode: &[u8], + ) -> eyre::Result { + self.deploys + .lock() + .unwrap() + .push((salt, initcode.to_vec())); + + // Simulate: place the expected runtime bytecode at the computed address + let address = compute_address(salt, initcode); + + // Determine which contract this is based on initcode + let runtime = + if initcode.len() > contracts::admin_proxy::ADMIN_PROXY_INITCODE.len() + && initcode[..contracts::admin_proxy::ADMIN_PROXY_INITCODE.len()] + == *contracts::admin_proxy::ADMIN_PROXY_INITCODE + { + Bytes::from_static(contracts::admin_proxy::ADMIN_PROXY_BYTECODE) + } else { + let runtime = contracts::permit2::expected_runtime_bytecode( + self.chain_id, + address, + ); + Bytes::from(runtime) + }; + + self.code.lock().unwrap().insert(address, runtime); + + Ok(TxReceipt { + tx_hash: B256::with_last_byte(0x01), + success: true, + }) + } + } + + fn test_config() -> DeployConfig { + DeployConfig { + chain: ChainConfig { chain_id: 1234 }, + contracts: ContractsConfig { + admin_proxy: Some(AdminProxyConfig { + address: None, + owner: address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), + }), + permit2: Some(Permit2Config { address: None }), + }, + } + } + + #[tokio::test] + async fn pipeline_deploys_both_contracts() { + let mock = MockDeployer::new(1234); + let tmp_state = tempfile::NamedTempFile::new().unwrap(); + std::fs::remove_file(tmp_state.path()).unwrap(); + + let cfg = PipelineConfig { + config: test_config(), + state_path: tmp_state.path().to_path_buf(), + addresses_out: None, + }; + + run(&cfg, &mock).await.unwrap(); + + let state = DeployState::load(tmp_state.path()).unwrap(); + assert_eq!( + state.contracts.admin_proxy.as_ref().unwrap().status, + ContractStatus::Verified + ); + assert_eq!( + state.contracts.permit2.as_ref().unwrap().status, + ContractStatus::Verified + ); + assert_eq!(mock.deploys.lock().unwrap().len(), 2); + } + + #[tokio::test] + async fn pipeline_skips_already_deployed() { + let mock = MockDeployer::new(1234); + let tmp_state = tempfile::NamedTempFile::new().unwrap(); + std::fs::remove_file(tmp_state.path()).unwrap(); + + let cfg = PipelineConfig { + config: test_config(), + state_path: tmp_state.path().to_path_buf(), + addresses_out: None, + }; + + // First run + run(&cfg, &mock).await.unwrap(); + assert_eq!(mock.deploys.lock().unwrap().len(), 2); + + // Second run — should skip both + run(&cfg, &mock).await.unwrap(); + assert_eq!(mock.deploys.lock().unwrap().len(), 2); // no new deploys + } + + #[tokio::test] + async fn pipeline_rejects_chain_id_mismatch() { + let mock = MockDeployer::new(9999); + let tmp_state = tempfile::NamedTempFile::new().unwrap(); + std::fs::remove_file(tmp_state.path()).unwrap(); + + let cfg = PipelineConfig { + config: test_config(), // chain_id = 1234 + state_path: tmp_state.path().to_path_buf(), + addresses_out: None, + }; + + let err = run(&cfg, &mock).await.unwrap_err().to_string(); + assert!(err.contains("chain_id mismatch"), "{err}"); + } + + #[tokio::test] + async fn pipeline_rejects_missing_deployer() { + let mock = MockDeployer::new(1234); + mock.code.lock().unwrap().remove(&DETERMINISTIC_DEPLOYER); + + let tmp_state = tempfile::NamedTempFile::new().unwrap(); + std::fs::remove_file(tmp_state.path()).unwrap(); + + let cfg = PipelineConfig { + config: test_config(), + state_path: tmp_state.path().to_path_buf(), + addresses_out: None, + }; + + let err = run(&cfg, &mock).await.unwrap_err().to_string(); + assert!(err.contains("deterministic deployer not found"), "{err}"); + } +} From 0c67446be63a71dd35ff6d69b530c9bdbd1ffdfc Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 17:32:30 +0200 Subject: [PATCH 07/18] feat(ev-deployer): wire up deploy subcommand in CLI --- bin/ev-deployer/src/main.rs | 48 ++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/bin/ev-deployer/src/main.rs b/bin/ev-deployer/src/main.rs index 57ec437..d622e24 100644 --- a/bin/ev-deployer/src/main.rs +++ b/bin/ev-deployer/src/main.rs @@ -1,4 +1,4 @@ -//! EV Deployer — genesis alloc generator for ev-reth contracts. +//! EV Deployer — genesis alloc generator and live deployer for ev-reth contracts. mod config; mod contracts; @@ -9,11 +9,11 @@ mod output; use clap::{Parser, Subcommand}; use std::path::PathBuf; -/// EV Deployer: generate genesis alloc entries for ev-reth contracts. +/// EV Deployer: generate genesis alloc or deploy ev-reth contracts. #[derive(Parser)] #[command( name = "ev-deployer", - about = "Generate genesis alloc for ev-reth contracts" + about = "Generate genesis alloc or deploy ev-reth contracts" )] struct Cli { #[command(subcommand)] @@ -50,6 +50,28 @@ enum Command { #[arg(long)] addresses_out: Option, }, + /// Deploy contracts to a live chain via CREATE2. + Deploy { + /// Path to the deploy TOML config. + #[arg(long)] + config: PathBuf, + + /// RPC URL of the target chain. + #[arg(long, env = "EV_DEPLOYER_RPC_URL")] + rpc_url: String, + + /// Hex-encoded private key for signing transactions. + #[arg(long, env = "EV_DEPLOYER_PRIVATE_KEY")] + private_key: String, + + /// Path to the state file (created if absent, resumed if present). + #[arg(long)] + state: PathBuf, + + /// Write an address manifest to this file. + #[arg(long)] + addresses_out: Option, + }, /// Compute the address for a configured contract. ComputeAddress { /// Path to the deploy TOML config. @@ -98,6 +120,26 @@ fn main() -> eyre::Result<()> { eprintln!("Wrote address manifest to {}", addr_path.display()); } } + Command::Deploy { + config: config_path, + rpc_url, + private_key, + state: state_path, + addresses_out, + } => { + let cfg = config::DeployConfig::load(&config_path)?; + let deployer = deploy::deployer::LiveDeployer::new(&rpc_url, &private_key)?; + let pipeline_cfg = deploy::pipeline::PipelineConfig { + config: cfg, + state_path, + addresses_out, + }; + + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build()? + .block_on(deploy::pipeline::run(&pipeline_cfg, &deployer))?; + } Command::Init { output } => { let template = include_str!("init_template.toml"); From 308ac0efb07b1416c38d5084c597bcb5097dac0c Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 17:32:46 +0200 Subject: [PATCH 08/18] docs(ev-deployer): update init template for deploy mode --- bin/ev-deployer/src/init_template.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/ev-deployer/src/init_template.toml b/bin/ev-deployer/src/init_template.toml index e44eb6f..966e5eb 100644 --- a/bin/ev-deployer/src/init_template.toml +++ b/bin/ev-deployer/src/init_template.toml @@ -6,8 +6,9 @@ chain_id = 0 # ── Contracts ──────────────────────────────────────────── -# Uncomment and configure the contracts you want to include -# in the genesis alloc. +# Uncomment and configure the contracts you want to deploy. +# The `address` field is required for `genesis` mode but +# ignored in `deploy` mode (addresses come from CREATE2). # AdminProxy: transparent proxy with owner-based access control. # The owner address is stored in slot 0. From cbdaaa232fffed8dfd75c9be80fd3b8b0ec6a326 Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 17:34:26 +0200 Subject: [PATCH 09/18] style(ev-deployer): fix rustfmt formatting --- bin/ev-deployer/src/contracts/admin_proxy.rs | 1 - bin/ev-deployer/src/deploy/create2.rs | 7 ++-- bin/ev-deployer/src/deploy/deployer.rs | 4 +- bin/ev-deployer/src/deploy/pipeline.rs | 39 +++++++------------- bin/ev-deployer/src/deploy/state.rs | 10 ++--- bin/ev-deployer/src/output.rs | 5 +-- 6 files changed, 25 insertions(+), 41 deletions(-) diff --git a/bin/ev-deployer/src/contracts/admin_proxy.rs b/bin/ev-deployer/src/contracts/admin_proxy.rs index 4709eb0..fc1eea1 100644 --- a/bin/ev-deployer/src/contracts/admin_proxy.rs +++ b/bin/ev-deployer/src/contracts/admin_proxy.rs @@ -12,7 +12,6 @@ pub(crate) const ADMIN_PROXY_BYTECODE: &[u8] = &hex!("60806040526004361061007e57 /// Regenerate with: `cd contracts && forge inspect AdminProxy bytecode` pub(crate) const ADMIN_PROXY_INITCODE: &[u8] = &hex!("6080604052348015600e575f5ffd5b506112ab8061001c5f395ff3fe60806040526004361061007e575f3560e01c80638da5cb5b1161004d5780638da5cb5b1461012d578063e30c397814610157578063f2fde38b14610181578063fa4bb79d146101a957610085565b806318dfb3c7146100895780631cff79cd146100c557806379ba5097146101015780638b5298541461011757610085565b3661008557005b5f5ffd5b348015610094575f5ffd5b506100af60048036038101906100aa9190610cf8565b6101e5565b6040516100bc9190610ea1565b60405180910390f35b3480156100d0575f5ffd5b506100eb60048036038101906100e69190610f70565b6104d9565b6040516100f89190611015565b60405180910390f35b34801561010c575f5ffd5b5061011561066c565b005b348015610122575f5ffd5b5061012b6107ed565b005b348015610138575f5ffd5b506101416108b4565b60405161014e9190611044565b60405180910390f35b348015610162575f5ffd5b5061016b6108d8565b6040516101789190611044565b60405180910390f35b34801561018c575f5ffd5b506101a760048036038101906101a2919061105d565b6108fd565b005b3480156101b4575f5ffd5b506101cf60048036038101906101ca91906110bb565b610aa4565b6040516101dc9190611015565b60405180910390f35b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026c576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282905085859050146102ab576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484905067ffffffffffffffff8111156102c8576102c761112c565b5b6040519080825280602002602001820160405280156102fb57816020015b60608152602001906001900390816102e65790505b5090505f5f90505b858590508110156104d0575f5f87878481811061032357610322611159565b5b9050602002016020810190610338919061105d565b73ffffffffffffffffffffffffffffffffffffffff1686868581811061036157610360611159565b5b90506020028101906103739190611192565b604051610381929190611230565b5f604051808303815f865af19150503d805f81146103ba576040519150601f19603f3d011682016040523d82523d5f602084013e6103bf565b606091505b50915091508161040657806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016103fd9190611015565b60405180910390fd5b87878481811061041957610418611159565b5b905060200201602081019061042e919061105d565b73ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb587878681811061047857610477611159565b5b905060200281019061048a9190611192565b8460405161049a93929190611274565b60405180910390a2808484815181106104b6576104b5611159565b5b602002602001018190525050508080600101915050610303565b50949350505050565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610560576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8573ffffffffffffffffffffffffffffffffffffffff168585604051610589929190611230565b5f604051808303815f865af19150503d805f81146105c2576040519150601f19603f3d011682016040523d82523d5f602084013e6105c7565b606091505b50915091508161060e57806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016106059190611015565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb586868460405161065893929190611274565b60405180910390a280925050509392505050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106f2576040517f1853971c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3335f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610872576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610982576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036109e7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b2b576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff16848787604051610b55929190611230565b5f6040518083038185875af1925050503d805f8114610b8f576040519150601f19603f3d011682016040523d82523d5f602084013e610b94565b606091505b509150915081610bdb57806040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152600401610bd29190611015565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb5878784604051610c2593929190611274565b60405180910390a28092505050949350505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112610c6357610c62610c42565b5b8235905067ffffffffffffffff811115610c8057610c7f610c46565b5b602083019150836020820283011115610c9c57610c9b610c4a565b5b9250929050565b5f5f83601f840112610cb857610cb7610c42565b5b8235905067ffffffffffffffff811115610cd557610cd4610c46565b5b602083019150836020820283011115610cf157610cf0610c4a565b5b9250929050565b5f5f5f5f60408587031215610d1057610d0f610c3a565b5b5f85013567ffffffffffffffff811115610d2d57610d2c610c3e565b5b610d3987828801610c4e565b9450945050602085013567ffffffffffffffff811115610d5c57610d5b610c3e565b5b610d6887828801610ca3565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610de182610d9f565b610deb8185610da9565b9350610dfb818560208601610db9565b610e0481610dc7565b840191505092915050565b5f610e1a8383610dd7565b905092915050565b5f602082019050919050565b5f610e3882610d76565b610e428185610d80565b935083602082028501610e5485610d90565b805f5b85811015610e8f5784840389528151610e708582610e0f565b9450610e7b83610e22565b925060208a01995050600181019050610e57565b50829750879550505050505092915050565b5f6020820190508181035f830152610eb98184610e2e565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610eea82610ec1565b9050919050565b610efa81610ee0565b8114610f04575f5ffd5b50565b5f81359050610f1581610ef1565b92915050565b5f5f83601f840112610f3057610f2f610c42565b5b8235905067ffffffffffffffff811115610f4d57610f4c610c46565b5b602083019150836001820283011115610f6957610f68610c4a565b5b9250929050565b5f5f5f60408486031215610f8757610f86610c3a565b5b5f610f9486828701610f07565b935050602084013567ffffffffffffffff811115610fb557610fb4610c3e565b5b610fc186828701610f1b565b92509250509250925092565b5f82825260208201905092915050565b5f610fe782610d9f565b610ff18185610fcd565b9350611001818560208601610db9565b61100a81610dc7565b840191505092915050565b5f6020820190508181035f83015261102d8184610fdd565b905092915050565b61103e81610ee0565b82525050565b5f6020820190506110575f830184611035565b92915050565b5f6020828403121561107257611071610c3a565b5b5f61107f84828501610f07565b91505092915050565b5f819050919050565b61109a81611088565b81146110a4575f5ffd5b50565b5f813590506110b581611091565b92915050565b5f5f5f5f606085870312156110d3576110d2610c3a565b5b5f6110e087828801610f07565b945050602085013567ffffffffffffffff81111561110157611100610c3e565b5b61110d87828801610f1b565b93509350506040611120878288016110a7565b91505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126111ae576111ad611186565b5b80840192508235915067ffffffffffffffff8211156111d0576111cf61118a565b5b6020830192506001820236038313156111ec576111eb61118e565b5b509250929050565b5f81905092915050565b828183375f83830152505050565b5f61121783856111f4565b93506112248385846111fe565b82840190509392505050565b5f61123c82848661120c565b91508190509392505050565b5f6112538385610fcd565b93506112608385846111fe565b61126983610dc7565b840190509392505050565b5f6040820190508181035f83015261128d818587611248565b905081810360208301526112a18184610fdd565b905094935050505056"); - /// Build a genesis alloc entry for `AdminProxy`. pub(crate) fn build(config: &AdminProxyConfig) -> GenesisContract { let address = config.address.expect("address required for genesis"); diff --git a/bin/ev-deployer/src/deploy/create2.rs b/bin/ev-deployer/src/deploy/create2.rs index b1d8deb..970b860 100644 --- a/bin/ev-deployer/src/deploy/create2.rs +++ b/bin/ev-deployer/src/deploy/create2.rs @@ -1,11 +1,12 @@ //! CREATE2 address computation. -use alloy_primitives::{Address, Bytes, B256, keccak256}; +use alloy_primitives::{keccak256, Address, Bytes, B256}; /// The deterministic deployer factory address (Nick's factory). /// See: https://github.com/Arachnid/deterministic-deployment-proxy -pub(crate) const DETERMINISTIC_DEPLOYER: Address = - Address::new(alloy_primitives::hex!("4e59b44847b379578588920ca78fbf26c0b4956c")); +pub(crate) const DETERMINISTIC_DEPLOYER: Address = Address::new(alloy_primitives::hex!( + "4e59b44847b379578588920ca78fbf26c0b4956c" +)); /// Compute the CREATE2 address for a contract deployed via the deterministic deployer. /// diff --git a/bin/ev-deployer/src/deploy/deployer.rs b/bin/ev-deployer/src/deploy/deployer.rs index 8fa9571..bff3bef 100644 --- a/bin/ev-deployer/src/deploy/deployer.rs +++ b/bin/ev-deployer/src/deploy/deployer.rs @@ -37,7 +37,9 @@ pub(crate) struct LiveDeployer { impl LiveDeployer { /// Create a new LiveDeployer from an RPC URL and a hex-encoded private key. pub(crate) fn new(rpc_url: &str, private_key_hex: &str) -> eyre::Result { - let key_hex = private_key_hex.strip_prefix("0x").unwrap_or(private_key_hex); + let key_hex = private_key_hex + .strip_prefix("0x") + .unwrap_or(private_key_hex); let signer: PrivateKeySigner = key_hex.parse()?; let wallet = EthereumWallet::from(signer); diff --git a/bin/ev-deployer/src/deploy/pipeline.rs b/bin/ev-deployer/src/deploy/pipeline.rs index 5dbf5b0..5b96577 100644 --- a/bin/ev-deployer/src/deploy/pipeline.rs +++ b/bin/ev-deployer/src/deploy/pipeline.rs @@ -99,8 +99,7 @@ pub(crate) async fn run( let initcode = contracts::permit2::PERMIT2_INITCODE.to_vec(); let address = compute_address(salt, &initcode); - let expected_runtime = - contracts::permit2::expected_runtime_bytecode(chain_id, address); + let expected_runtime = contracts::permit2::expected_runtime_bytecode(chain_id, address); deploy_contract( deployer, @@ -242,8 +241,7 @@ async fn verify_all( if let Some(ref cs) = state.contracts.permit2 { if cs.status == ContractStatus::Deployed { let on_chain = deployer.get_code(cs.address).await?; - let expected = - contracts::permit2::expected_runtime_bytecode(chain_id, cs.address); + let expected = contracts::permit2::expected_runtime_bytecode(chain_id, cs.address); eyre::ensure!( on_chain.as_ref() == expected.as_slice(), "bytecode mismatch at {}: expected {} bytes, got {} bytes", @@ -338,33 +336,22 @@ mod tests { .unwrap_or_default()) } - async fn deploy_create2( - &self, - salt: B256, - initcode: &[u8], - ) -> eyre::Result { - self.deploys - .lock() - .unwrap() - .push((salt, initcode.to_vec())); + async fn deploy_create2(&self, salt: B256, initcode: &[u8]) -> eyre::Result { + self.deploys.lock().unwrap().push((salt, initcode.to_vec())); // Simulate: place the expected runtime bytecode at the computed address let address = compute_address(salt, initcode); // Determine which contract this is based on initcode - let runtime = - if initcode.len() > contracts::admin_proxy::ADMIN_PROXY_INITCODE.len() - && initcode[..contracts::admin_proxy::ADMIN_PROXY_INITCODE.len()] - == *contracts::admin_proxy::ADMIN_PROXY_INITCODE - { - Bytes::from_static(contracts::admin_proxy::ADMIN_PROXY_BYTECODE) - } else { - let runtime = contracts::permit2::expected_runtime_bytecode( - self.chain_id, - address, - ); - Bytes::from(runtime) - }; + let runtime = if initcode.len() > contracts::admin_proxy::ADMIN_PROXY_INITCODE.len() + && initcode[..contracts::admin_proxy::ADMIN_PROXY_INITCODE.len()] + == *contracts::admin_proxy::ADMIN_PROXY_INITCODE + { + Bytes::from_static(contracts::admin_proxy::ADMIN_PROXY_BYTECODE) + } else { + let runtime = contracts::permit2::expected_runtime_bytecode(self.chain_id, address); + Bytes::from(runtime) + }; self.code.lock().unwrap().insert(address, runtime); diff --git a/bin/ev-deployer/src/deploy/state.rs b/bin/ev-deployer/src/deploy/state.rs index a3adefd..8fad046 100644 --- a/bin/ev-deployer/src/deploy/state.rs +++ b/bin/ev-deployer/src/deploy/state.rs @@ -122,7 +122,9 @@ impl DeployState { new_ap.owner ); } else { - eyre::bail!("immutability violation: admin_proxy was configured but is now missing"); + eyre::bail!( + "immutability violation: admin_proxy was configured but is now missing" + ); } } @@ -147,11 +149,7 @@ impl AppliedIntent { .admin_proxy .as_ref() .map(|ap| AppliedAdminProxy { owner: ap.owner }), - permit2: config - .contracts - .permit2 - .as_ref() - .map(|_| AppliedPermit2 {}), + permit2: config.contracts.permit2.as_ref().map(|_| AppliedPermit2 {}), } } } diff --git a/bin/ev-deployer/src/output.rs b/bin/ev-deployer/src/output.rs index d434974..8053180 100644 --- a/bin/ev-deployer/src/output.rs +++ b/bin/ev-deployer/src/output.rs @@ -18,10 +18,7 @@ pub(crate) fn build_manifest(config: &DeployConfig) -> Value { if let Some(ref p2) = config.contracts.permit2 { if let Some(addr) = p2.address { - manifest.insert( - "permit2".to_string(), - Value::String(format!("{}", addr)), - ); + manifest.insert("permit2".to_string(), Value::String(format!("{}", addr))); } } From 58dd78aecdad422137443d2a01b7093f0966d667 Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 17:46:14 +0200 Subject: [PATCH 10/18] chore: update Cargo.lock for ev-deployer deploy dependencies --- Cargo.lock | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index ef8c2de..48a6536 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2921,12 +2921,18 @@ dependencies = [ name = "ev-deployer" version = "0.1.0" dependencies = [ + "alloy", "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-signer-local", + "async-trait", "clap", "eyre", + "rand 0.10.0", "serde", "serde_json", "tempfile", + "tokio", "toml 0.8.23", ] From 868bd3ad946fb07c1025fa05d08cd6a345edb9ec Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 17:54:33 +0200 Subject: [PATCH 11/18] fix(ev-deployer): address clippy lints and nightly rustfmt imports --- bin/ev-deployer/src/deploy/create2.rs | 4 +- bin/ev-deployer/src/deploy/deployer.rs | 10 ++- bin/ev-deployer/src/deploy/pipeline.rs | 108 ++++++++++++++----------- bin/ev-deployer/src/deploy/state.rs | 17 ++-- 4 files changed, 74 insertions(+), 65 deletions(-) diff --git a/bin/ev-deployer/src/deploy/create2.rs b/bin/ev-deployer/src/deploy/create2.rs index 970b860..cb3b3cf 100644 --- a/bin/ev-deployer/src/deploy/create2.rs +++ b/bin/ev-deployer/src/deploy/create2.rs @@ -3,7 +3,7 @@ use alloy_primitives::{keccak256, Address, Bytes, B256}; /// The deterministic deployer factory address (Nick's factory). -/// See: https://github.com/Arachnid/deterministic-deployment-proxy +/// See: pub(crate) const DETERMINISTIC_DEPLOYER: Address = Address::new(alloy_primitives::hex!( "4e59b44847b379578588920ca78fbf26c0b4956c" )); @@ -41,7 +41,7 @@ mod tests { let initcode = hex!("60006000f3"); let addr = compute_address(salt, &initcode); - let init_hash = keccak256(&initcode); + let init_hash = keccak256(initcode); let expected = DETERMINISTIC_DEPLOYER.create2(salt, init_hash); assert_eq!(addr, expected); } diff --git a/bin/ev-deployer/src/deploy/deployer.rs b/bin/ev-deployer/src/deploy/deployer.rs index bff3bef..a673e2a 100644 --- a/bin/ev-deployer/src/deploy/deployer.rs +++ b/bin/ev-deployer/src/deploy/deployer.rs @@ -1,8 +1,10 @@ -//! ChainDeployer trait and LiveDeployer implementation. +//! `ChainDeployer` trait and `LiveDeployer` implementation. use crate::deploy::create2::{build_factory_calldata, DETERMINISTIC_DEPLOYER}; -use alloy::network::EthereumWallet; -use alloy::providers::{Provider, ProviderBuilder}; +use alloy::{ + network::EthereumWallet, + providers::{Provider, ProviderBuilder}, +}; use alloy_primitives::{Address, Bytes, B256}; use alloy_rpc_types_eth::TransactionRequest; use alloy_signer_local::PrivateKeySigner; @@ -35,7 +37,7 @@ pub(crate) struct LiveDeployer { } impl LiveDeployer { - /// Create a new LiveDeployer from an RPC URL and a hex-encoded private key. + /// Create a new `LiveDeployer` from an RPC URL and a hex-encoded private key. pub(crate) fn new(rpc_url: &str, private_key_hex: &str) -> eyre::Result { let key_hex = private_key_hex .strip_prefix("0x") diff --git a/bin/ev-deployer/src/deploy/pipeline.rs b/bin/ev-deployer/src/deploy/pipeline.rs index 5b96577..4b1256b 100644 --- a/bin/ev-deployer/src/deploy/pipeline.rs +++ b/bin/ev-deployer/src/deploy/pipeline.rs @@ -1,10 +1,14 @@ //! Deploy pipeline: orchestrates the full deployment flow. -use crate::config::DeployConfig; -use crate::contracts; -use crate::deploy::create2::{compute_address, DETERMINISTIC_DEPLOYER}; -use crate::deploy::deployer::ChainDeployer; -use crate::deploy::state::{ContractState, ContractStatus, DeployState}; +use crate::{ + config::DeployConfig, + contracts, + deploy::{ + create2::{compute_address, DETERMINISTIC_DEPLOYER}, + deployer::ChainDeployer, + state::{ContractState, ContractStatus, DeployState}, + }, +}; use alloy_primitives::{Address, B256}; use std::path::{Path, PathBuf}; @@ -68,12 +72,14 @@ pub(crate) async fn run( deploy_contract( deployer, &mut state, - "admin_proxy", - address, - salt, - &initcode, - contracts::admin_proxy::ADMIN_PROXY_BYTECODE, - &pipeline_cfg.state_path, + &DeployContractParams { + name: "admin_proxy", + address, + salt, + initcode: &initcode, + expected_runtime: contracts::admin_proxy::ADMIN_PROXY_BYTECODE, + state_path: &pipeline_cfg.state_path, + }, ) .await?; } else { @@ -81,18 +87,10 @@ pub(crate) async fn run( } // ── Step 3: Deploy Permit2 ── - if pipeline_cfg.config.contracts.permit2.is_some() { + if let Some(ref p2_config) = pipeline_cfg.config.contracts.permit2 { eprintln!("[4/5] Deploying Permit2..."); - if pipeline_cfg - .config - .contracts - .permit2 - .as_ref() - .unwrap() - .address - .is_some() - { + if p2_config.address.is_some() { eprintln!(" WARN: contracts.permit2.address is ignored in deploy mode"); } @@ -104,12 +102,14 @@ pub(crate) async fn run( deploy_contract( deployer, &mut state, - "permit2", - address, - salt, - &initcode, - &expected_runtime, - &pipeline_cfg.state_path, + &DeployContractParams { + name: "permit2", + address, + salt, + initcode: &initcode, + expected_runtime: &expected_runtime, + state_path: &pipeline_cfg.state_path, + }, ) .await?; } else { @@ -139,7 +139,7 @@ pub(crate) async fn run( Ok(()) } -/// Build AdminProxy initcode with constructor argument. +/// Build `AdminProxy` initcode with constructor argument. fn build_admin_proxy_initcode(owner: Address) -> Vec { let mut initcode = contracts::admin_proxy::ADMIN_PROXY_INITCODE.to_vec(); // ABI-encode the owner address as a 32-byte word and append @@ -147,17 +147,30 @@ fn build_admin_proxy_initcode(owner: Address) -> Vec { initcode } +/// Parameters for deploying a single contract. +struct DeployContractParams<'a> { + name: &'a str, + address: Address, + salt: B256, + initcode: &'a [u8], + expected_runtime: &'a [u8], + state_path: &'a Path, +} + /// Deploy a single contract via CREATE2 with idempotency. async fn deploy_contract( deployer: &dyn ChainDeployer, state: &mut DeployState, - name: &str, - address: Address, - salt: B256, - initcode: &[u8], - expected_runtime: &[u8], - state_path: &Path, + params: &DeployContractParams<'_>, ) -> eyre::Result<()> { + let DeployContractParams { + name, + address, + salt, + initcode, + expected_runtime, + state_path, + } = params; // Check if already deployed or verified in state let current_status = get_contract_status(state, name); if current_status >= Some(ContractStatus::Deployed) { @@ -166,32 +179,31 @@ async fn deploy_contract( } // Idempotency: check if code already exists on-chain - let existing_code = deployer.get_code(address).await?; + let existing_code = deployer.get_code(*address).await?; if !existing_code.is_empty() { - if existing_code.as_ref() == expected_runtime { + if existing_code.as_ref() == *expected_runtime { eprintln!(" found matching bytecode at {address}, marking as deployed"); set_contract_state( state, name, ContractState { status: ContractStatus::Deployed, - address, + address: *address, deploy_tx: None, }, ); state.save(state_path)?; return Ok(()); - } else { - eyre::bail!( - "unexpected bytecode at {address}: expected {} bytes, found {} bytes", - expected_runtime.len(), - existing_code.len() - ); } + eyre::bail!( + "unexpected bytecode at {address}: expected {} bytes, found {} bytes", + expected_runtime.len(), + existing_code.len() + ); } // Deploy - let receipt = deployer.deploy_create2(salt, initcode).await?; + let receipt = deployer.deploy_create2(*salt, initcode).await?; eyre::ensure!( receipt.success, "CREATE2 deploy tx reverted for {name}: tx={}", @@ -205,7 +217,7 @@ async fn deploy_contract( name, ContractState { status: ContractStatus::Deployed, - address, + address: *address, deploy_tx: Some(receipt.tx_hash), }, ); @@ -294,12 +306,10 @@ fn build_deploy_manifest(state: &DeployState) -> serde_json::Value { #[cfg(test)] mod tests { use super::*; - use crate::config::*; - use crate::deploy::deployer::TxReceipt; + use crate::{config::*, deploy::deployer::TxReceipt}; use alloy_primitives::{address, Bytes}; use async_trait::async_trait; - use std::collections::HashMap; - use std::sync::Mutex; + use std::{collections::HashMap, sync::Mutex}; /// Mock deployer for testing the pipeline without a live chain. struct MockDeployer { diff --git a/bin/ev-deployer/src/deploy/state.rs b/bin/ev-deployer/src/deploy/state.rs index 8fad046..17759aa 100644 --- a/bin/ev-deployer/src/deploy/state.rs +++ b/bin/ev-deployer/src/deploy/state.rs @@ -207,9 +207,8 @@ mod tests { #[test] fn immutability_rejects_chain_id_change() { - let config = test_config(); - let state = DeployState::new(&config); - let mut changed = config.clone(); + let mut changed = test_config(); + let state = DeployState::new(&changed); changed.chain.chain_id = 9999; let err = state .validate_immutability(&changed) @@ -220,9 +219,8 @@ mod tests { #[test] fn immutability_rejects_owner_change() { - let config = test_config(); - let state = DeployState::new(&config); - let mut changed = config.clone(); + let mut changed = test_config(); + let state = DeployState::new(&changed); changed.contracts.admin_proxy.as_mut().unwrap().owner = address!("0000000000000000000000000000000000000001"); let err = state @@ -247,16 +245,15 @@ mod tests { let state = DeployState::new(&config); // Now add permit2 — this should be allowed - let mut extended = config.clone(); + let mut extended = config; extended.contracts.permit2 = Some(Permit2Config { address: None }); assert!(state.validate_immutability(&extended).is_ok()); } #[test] fn immutability_rejects_removing_contract() { - let config = test_config(); - let state = DeployState::new(&config); - let mut changed = config.clone(); + let mut changed = test_config(); + let state = DeployState::new(&changed); changed.contracts.admin_proxy = None; let err = state .validate_immutability(&changed) From 77c098be4835caf20cf36c5c001d0231eab349ee Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 18:26:13 +0200 Subject: [PATCH 12/18] fix(ev-deployer): remove AdminProxy from deploy pipeline AdminProxy has an empty constructor and sets owner via genesis storage slot 0, making it incompatible with live CREATE2 deployment where the owner would remain address(0). Restrict AdminProxy to genesis-only mode. --- bin/ev-deployer/src/contracts/admin_proxy.rs | 5 - bin/ev-deployer/src/deploy/pipeline.rs | 125 ++++--------------- bin/ev-deployer/src/deploy/state.rs | 62 +-------- 3 files changed, 31 insertions(+), 161 deletions(-) diff --git a/bin/ev-deployer/src/contracts/admin_proxy.rs b/bin/ev-deployer/src/contracts/admin_proxy.rs index fc1eea1..defa9c2 100644 --- a/bin/ev-deployer/src/contracts/admin_proxy.rs +++ b/bin/ev-deployer/src/contracts/admin_proxy.rs @@ -7,11 +7,6 @@ use std::collections::BTreeMap; /// `AdminProxy` runtime bytecode compiled with solc 0.8.33 (`cbor_metadata=false`). /// Regenerate with: `cd contracts && forge inspect AdminProxy deployedBytecode` pub(crate) const ADMIN_PROXY_BYTECODE: &[u8] = &hex!("60806040526004361061007e575f3560e01c80638da5cb5b1161004d5780638da5cb5b1461012d578063e30c397814610157578063f2fde38b14610181578063fa4bb79d146101a957610085565b806318dfb3c7146100895780631cff79cd146100c557806379ba5097146101015780638b5298541461011757610085565b3661008557005b5f5ffd5b348015610094575f5ffd5b506100af60048036038101906100aa9190610cf8565b6101e5565b6040516100bc9190610ea1565b60405180910390f35b3480156100d0575f5ffd5b506100eb60048036038101906100e69190610f70565b6104d9565b6040516100f89190611015565b60405180910390f35b34801561010c575f5ffd5b5061011561066c565b005b348015610122575f5ffd5b5061012b6107ed565b005b348015610138575f5ffd5b506101416108b4565b60405161014e9190611044565b60405180910390f35b348015610162575f5ffd5b5061016b6108d8565b6040516101789190611044565b60405180910390f35b34801561018c575f5ffd5b506101a760048036038101906101a2919061105d565b6108fd565b005b3480156101b4575f5ffd5b506101cf60048036038101906101ca91906110bb565b610aa4565b6040516101dc9190611015565b60405180910390f35b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026c576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282905085859050146102ab576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484905067ffffffffffffffff8111156102c8576102c761112c565b5b6040519080825280602002602001820160405280156102fb57816020015b60608152602001906001900390816102e65790505b5090505f5f90505b858590508110156104d0575f5f87878481811061032357610322611159565b5b9050602002016020810190610338919061105d565b73ffffffffffffffffffffffffffffffffffffffff1686868581811061036157610360611159565b5b90506020028101906103739190611192565b604051610381929190611230565b5f604051808303815f865af19150503d805f81146103ba576040519150601f19603f3d011682016040523d82523d5f602084013e6103bf565b606091505b50915091508161040657806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016103fd9190611015565b60405180910390fd5b87878481811061041957610418611159565b5b905060200201602081019061042e919061105d565b73ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb587878681811061047857610477611159565b5b905060200281019061048a9190611192565b8460405161049a93929190611274565b60405180910390a2808484815181106104b6576104b5611159565b5b602002602001018190525050508080600101915050610303565b50949350505050565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610560576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8573ffffffffffffffffffffffffffffffffffffffff168585604051610589929190611230565b5f604051808303815f865af19150503d805f81146105c2576040519150601f19603f3d011682016040523d82523d5f602084013e6105c7565b606091505b50915091508161060e57806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016106059190611015565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb586868460405161065893929190611274565b60405180910390a280925050509392505050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106f2576040517f1853971c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3335f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610872576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610982576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036109e7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b2b576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff16848787604051610b55929190611230565b5f6040518083038185875af1925050503d805f8114610b8f576040519150601f19603f3d011682016040523d82523d5f602084013e610b94565b606091505b509150915081610bdb57806040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152600401610bd29190611015565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb5878784604051610c2593929190611274565b60405180910390a28092505050949350505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112610c6357610c62610c42565b5b8235905067ffffffffffffffff811115610c8057610c7f610c46565b5b602083019150836020820283011115610c9c57610c9b610c4a565b5b9250929050565b5f5f83601f840112610cb857610cb7610c42565b5b8235905067ffffffffffffffff811115610cd557610cd4610c46565b5b602083019150836020820283011115610cf157610cf0610c4a565b5b9250929050565b5f5f5f5f60408587031215610d1057610d0f610c3a565b5b5f85013567ffffffffffffffff811115610d2d57610d2c610c3e565b5b610d3987828801610c4e565b9450945050602085013567ffffffffffffffff811115610d5c57610d5b610c3e565b5b610d6887828801610ca3565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610de182610d9f565b610deb8185610da9565b9350610dfb818560208601610db9565b610e0481610dc7565b840191505092915050565b5f610e1a8383610dd7565b905092915050565b5f602082019050919050565b5f610e3882610d76565b610e428185610d80565b935083602082028501610e5485610d90565b805f5b85811015610e8f5784840389528151610e708582610e0f565b9450610e7b83610e22565b925060208a01995050600181019050610e57565b50829750879550505050505092915050565b5f6020820190508181035f830152610eb98184610e2e565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610eea82610ec1565b9050919050565b610efa81610ee0565b8114610f04575f5ffd5b50565b5f81359050610f1581610ef1565b92915050565b5f5f83601f840112610f3057610f2f610c42565b5b8235905067ffffffffffffffff811115610f4d57610f4c610c46565b5b602083019150836001820283011115610f6957610f68610c4a565b5b9250929050565b5f5f5f60408486031215610f8757610f86610c3a565b5b5f610f9486828701610f07565b935050602084013567ffffffffffffffff811115610fb557610fb4610c3e565b5b610fc186828701610f1b565b92509250509250925092565b5f82825260208201905092915050565b5f610fe782610d9f565b610ff18185610fcd565b9350611001818560208601610db9565b61100a81610dc7565b840191505092915050565b5f6020820190508181035f83015261102d8184610fdd565b905092915050565b61103e81610ee0565b82525050565b5f6020820190506110575f830184611035565b92915050565b5f6020828403121561107257611071610c3a565b5b5f61107f84828501610f07565b91505092915050565b5f819050919050565b61109a81611088565b81146110a4575f5ffd5b50565b5f813590506110b581611091565b92915050565b5f5f5f5f606085870312156110d3576110d2610c3a565b5b5f6110e087828801610f07565b945050602085013567ffffffffffffffff81111561110157611100610c3e565b5b61110d87828801610f1b565b93509350506040611120878288016110a7565b91505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126111ae576111ad611186565b5b80840192508235915067ffffffffffffffff8211156111d0576111cf61118a565b5b6020830192506001820236038313156111ec576111eb61118e565b5b509250929050565b5f81905092915050565b828183375f83830152505050565b5f61121783856111f4565b93506112248385846111fe565b82840190509392505050565b5f61123c82848661120c565b91508190509392505050565b5f6112538385610fcd565b93506112608385846111fe565b61126983610dc7565b840190509392505050565b5f6040820190508181035f83015261128d818587611248565b905081810360208301526112a18184610fdd565b905094935050505056"); -/// `AdminProxy` creation bytecode (initcode) compiled with solc 0.8.33 (`cbor_metadata=false`). -/// The constructor is empty; owner is set via storage, not constructor args. -/// Regenerate with: `cd contracts && forge inspect AdminProxy bytecode` -pub(crate) const ADMIN_PROXY_INITCODE: &[u8] = &hex!("6080604052348015600e575f5ffd5b506112ab8061001c5f395ff3fe60806040526004361061007e575f3560e01c80638da5cb5b1161004d5780638da5cb5b1461012d578063e30c397814610157578063f2fde38b14610181578063fa4bb79d146101a957610085565b806318dfb3c7146100895780631cff79cd146100c557806379ba5097146101015780638b5298541461011757610085565b3661008557005b5f5ffd5b348015610094575f5ffd5b506100af60048036038101906100aa9190610cf8565b6101e5565b6040516100bc9190610ea1565b60405180910390f35b3480156100d0575f5ffd5b506100eb60048036038101906100e69190610f70565b6104d9565b6040516100f89190611015565b60405180910390f35b34801561010c575f5ffd5b5061011561066c565b005b348015610122575f5ffd5b5061012b6107ed565b005b348015610138575f5ffd5b506101416108b4565b60405161014e9190611044565b60405180910390f35b348015610162575f5ffd5b5061016b6108d8565b6040516101789190611044565b60405180910390f35b34801561018c575f5ffd5b506101a760048036038101906101a2919061105d565b6108fd565b005b3480156101b4575f5ffd5b506101cf60048036038101906101ca91906110bb565b610aa4565b6040516101dc9190611015565b60405180910390f35b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461026c576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282905085859050146102ab576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484905067ffffffffffffffff8111156102c8576102c761112c565b5b6040519080825280602002602001820160405280156102fb57816020015b60608152602001906001900390816102e65790505b5090505f5f90505b858590508110156104d0575f5f87878481811061032357610322611159565b5b9050602002016020810190610338919061105d565b73ffffffffffffffffffffffffffffffffffffffff1686868581811061036157610360611159565b5b90506020028101906103739190611192565b604051610381929190611230565b5f604051808303815f865af19150503d805f81146103ba576040519150601f19603f3d011682016040523d82523d5f602084013e6103bf565b606091505b50915091508161040657806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016103fd9190611015565b60405180910390fd5b87878481811061041957610418611159565b5b905060200201602081019061042e919061105d565b73ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb587878681811061047857610477611159565b5b905060200281019061048a9190611192565b8460405161049a93929190611274565b60405180910390a2808484815181106104b6576104b5611159565b5b602002602001018190525050508080600101915050610303565b50949350505050565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610560576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8573ffffffffffffffffffffffffffffffffffffffff168585604051610589929190611230565b5f604051808303815f865af19150503d805f81146105c2576040519150601f19603f3d011682016040523d82523d5f602084013e6105c7565b606091505b50915091508161060e57806040517fa5fa8d2b0000000000000000000000000000000000000000000000000000000081526004016106059190611015565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb586868460405161065893929190611274565b60405180910390a280925050509392505050565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106f2576040517f1853971c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3335f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610872576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610982576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036109e7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff165f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60605f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b2b576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff16848787604051610b55929190611230565b5f6040518083038185875af1925050503d805f8114610b8f576040519150601f19603f3d011682016040523d82523d5f602084013e610b94565b606091505b509150915081610bdb57806040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152600401610bd29190611015565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff167fc96720f35dd524e76ea92971ce13d08e9a17816bf3b0008a7083e6032354ebb5878784604051610c2593929190611274565b60405180910390a28092505050949350505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112610c6357610c62610c42565b5b8235905067ffffffffffffffff811115610c8057610c7f610c46565b5b602083019150836020820283011115610c9c57610c9b610c4a565b5b9250929050565b5f5f83601f840112610cb857610cb7610c42565b5b8235905067ffffffffffffffff811115610cd557610cd4610c46565b5b602083019150836020820283011115610cf157610cf0610c4a565b5b9250929050565b5f5f5f5f60408587031215610d1057610d0f610c3a565b5b5f85013567ffffffffffffffff811115610d2d57610d2c610c3e565b5b610d3987828801610c4e565b9450945050602085013567ffffffffffffffff811115610d5c57610d5b610c3e565b5b610d6887828801610ca3565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610de182610d9f565b610deb8185610da9565b9350610dfb818560208601610db9565b610e0481610dc7565b840191505092915050565b5f610e1a8383610dd7565b905092915050565b5f602082019050919050565b5f610e3882610d76565b610e428185610d80565b935083602082028501610e5485610d90565b805f5b85811015610e8f5784840389528151610e708582610e0f565b9450610e7b83610e22565b925060208a01995050600181019050610e57565b50829750879550505050505092915050565b5f6020820190508181035f830152610eb98184610e2e565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610eea82610ec1565b9050919050565b610efa81610ee0565b8114610f04575f5ffd5b50565b5f81359050610f1581610ef1565b92915050565b5f5f83601f840112610f3057610f2f610c42565b5b8235905067ffffffffffffffff811115610f4d57610f4c610c46565b5b602083019150836001820283011115610f6957610f68610c4a565b5b9250929050565b5f5f5f60408486031215610f8757610f86610c3a565b5b5f610f9486828701610f07565b935050602084013567ffffffffffffffff811115610fb557610fb4610c3e565b5b610fc186828701610f1b565b92509250509250925092565b5f82825260208201905092915050565b5f610fe782610d9f565b610ff18185610fcd565b9350611001818560208601610db9565b61100a81610dc7565b840191505092915050565b5f6020820190508181035f83015261102d8184610fdd565b905092915050565b61103e81610ee0565b82525050565b5f6020820190506110575f830184611035565b92915050565b5f6020828403121561107257611071610c3a565b5b5f61107f84828501610f07565b91505092915050565b5f819050919050565b61109a81611088565b81146110a4575f5ffd5b50565b5f813590506110b581611091565b92915050565b5f5f5f5f606085870312156110d3576110d2610c3a565b5b5f6110e087828801610f07565b945050602085013567ffffffffffffffff81111561110157611100610c3e565b5b61110d87828801610f1b565b93509350506040611120878288016110a7565b91505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126111ae576111ad611186565b5b80840192508235915067ffffffffffffffff8211156111d0576111cf61118a565b5b6020830192506001820236038313156111ec576111eb61118e565b5b509250929050565b5f81905092915050565b828183375f83830152505050565b5f61121783856111f4565b93506112248385846111fe565b82840190509392505050565b5f61123c82848661120c565b91508190509392505050565b5f6112538385610fcd565b93506112608385846111fe565b61126983610dc7565b840190509392505050565b5f6040820190508181035f83015261128d818587611248565b905081810360208301526112a18184610fdd565b905094935050505056"); - /// Build a genesis alloc entry for `AdminProxy`. pub(crate) fn build(config: &AdminProxyConfig) -> GenesisContract { let address = config.address.expect("address required for genesis"); diff --git a/bin/ev-deployer/src/deploy/pipeline.rs b/bin/ev-deployer/src/deploy/pipeline.rs index 4b1256b..9db2ead 100644 --- a/bin/ev-deployer/src/deploy/pipeline.rs +++ b/bin/ev-deployer/src/deploy/pipeline.rs @@ -25,7 +25,7 @@ pub(crate) async fn run( deployer: &dyn ChainDeployer, ) -> eyre::Result<()> { // ── Step 1: Init ── - eprintln!("[1/5] Connecting to RPC..."); + eprintln!("[1/4] Connecting to RPC..."); let chain_id = deployer.chain_id().await?; eprintln!(" chain_id={chain_id}"); @@ -36,7 +36,7 @@ pub(crate) async fn run( chain_id ); - eprintln!("[2/5] Verifying deterministic deployer..."); + eprintln!("[2/4] Verifying deterministic deployer..."); let deployer_code = deployer.get_code(DETERMINISTIC_DEPLOYER).await?; eyre::ensure!( !deployer_code.is_empty(), @@ -58,37 +58,9 @@ pub(crate) async fn run( let salt = state.create2_salt; - // ── Step 2: Deploy AdminProxy ── - if let Some(ref ap_config) = pipeline_cfg.config.contracts.admin_proxy { - eprintln!("[3/5] Deploying AdminProxy..."); - - if ap_config.address.is_some() { - eprintln!(" WARN: contracts.admin_proxy.address is ignored in deploy mode"); - } - - let initcode = build_admin_proxy_initcode(ap_config.owner); - let address = compute_address(salt, &initcode); - - deploy_contract( - deployer, - &mut state, - &DeployContractParams { - name: "admin_proxy", - address, - salt, - initcode: &initcode, - expected_runtime: contracts::admin_proxy::ADMIN_PROXY_BYTECODE, - state_path: &pipeline_cfg.state_path, - }, - ) - .await?; - } else { - eprintln!("[3/5] AdminProxy not configured, skipping"); - } - - // ── Step 3: Deploy Permit2 ── + // ── Step 2: Deploy Permit2 ── if let Some(ref p2_config) = pipeline_cfg.config.contracts.permit2 { - eprintln!("[4/5] Deploying Permit2..."); + eprintln!("[3/4] Deploying Permit2..."); if p2_config.address.is_some() { eprintln!(" WARN: contracts.permit2.address is ignored in deploy mode"); @@ -113,11 +85,11 @@ pub(crate) async fn run( ) .await?; } else { - eprintln!("[4/5] Permit2 not configured, skipping"); + eprintln!("[3/4] Permit2 not configured, skipping"); } - // ── Step 4: Verify ── - eprintln!("[5/5] Verifying bytecodes..."); + // ── Step 3: Verify ── + eprintln!("[4/4] Verifying bytecodes..."); verify_all(deployer, &mut state, &pipeline_cfg.config, chain_id).await?; state.save(&pipeline_cfg.state_path)?; eprintln!(" OK"); @@ -139,14 +111,6 @@ pub(crate) async fn run( Ok(()) } -/// Build `AdminProxy` initcode with constructor argument. -fn build_admin_proxy_initcode(owner: Address) -> Vec { - let mut initcode = contracts::admin_proxy::ADMIN_PROXY_INITCODE.to_vec(); - // ABI-encode the owner address as a 32-byte word and append - initcode.extend_from_slice(owner.into_word().as_slice()); - initcode -} - /// Parameters for deploying a single contract. struct DeployContractParams<'a> { name: &'a str, @@ -233,23 +197,6 @@ async fn verify_all( _config: &DeployConfig, chain_id: u64, ) -> eyre::Result<()> { - if let Some(ref cs) = state.contracts.admin_proxy { - if cs.status == ContractStatus::Deployed { - let on_chain = deployer.get_code(cs.address).await?; - let expected = contracts::admin_proxy::ADMIN_PROXY_BYTECODE; - eyre::ensure!( - on_chain.as_ref() == expected, - "bytecode mismatch at {}: expected {} bytes, got {} bytes", - cs.address, - expected.len(), - on_chain.len() - ); - let mut updated = cs.clone(); - updated.status = ContractStatus::Verified; - state.contracts.admin_proxy = Some(updated); - } - } - if let Some(ref cs) = state.contracts.permit2 { if cs.status == ContractStatus::Deployed { let on_chain = deployer.get_code(cs.address).await?; @@ -271,29 +218,21 @@ async fn verify_all( } fn get_contract_status(state: &DeployState, name: &str) -> Option { - match name { - "admin_proxy" => state.contracts.admin_proxy.as_ref().map(|c| c.status), - "permit2" => state.contracts.permit2.as_ref().map(|c| c.status), - _ => None, + if name == "permit2" { + state.contracts.permit2.as_ref().map(|c| c.status) + } else { + None } } fn set_contract_state(state: &mut DeployState, name: &str, cs: ContractState) { - match name { - "admin_proxy" => state.contracts.admin_proxy = Some(cs), - "permit2" => state.contracts.permit2 = Some(cs), - _ => {} + if name == "permit2" { + state.contracts.permit2 = Some(cs); } } fn build_deploy_manifest(state: &DeployState) -> serde_json::Value { let mut manifest = serde_json::Map::new(); - if let Some(ref cs) = state.contracts.admin_proxy { - manifest.insert( - "admin_proxy".to_string(), - serde_json::Value::String(format!("{}", cs.address)), - ); - } if let Some(ref cs) = state.contracts.permit2 { manifest.insert( "permit2".to_string(), @@ -307,7 +246,7 @@ fn build_deploy_manifest(state: &DeployState) -> serde_json::Value { mod tests { use super::*; use crate::{config::*, deploy::deployer::TxReceipt}; - use alloy_primitives::{address, Bytes}; + use alloy_primitives::Bytes; use async_trait::async_trait; use std::{collections::HashMap, sync::Mutex}; @@ -352,18 +291,11 @@ mod tests { // Simulate: place the expected runtime bytecode at the computed address let address = compute_address(salt, initcode); - // Determine which contract this is based on initcode - let runtime = if initcode.len() > contracts::admin_proxy::ADMIN_PROXY_INITCODE.len() - && initcode[..contracts::admin_proxy::ADMIN_PROXY_INITCODE.len()] - == *contracts::admin_proxy::ADMIN_PROXY_INITCODE - { - Bytes::from_static(contracts::admin_proxy::ADMIN_PROXY_BYTECODE) - } else { - let runtime = contracts::permit2::expected_runtime_bytecode(self.chain_id, address); - Bytes::from(runtime) - }; - - self.code.lock().unwrap().insert(address, runtime); + let runtime = contracts::permit2::expected_runtime_bytecode(self.chain_id, address); + self.code + .lock() + .unwrap() + .insert(address, Bytes::from(runtime)); Ok(TxReceipt { tx_hash: B256::with_last_byte(0x01), @@ -376,17 +308,14 @@ mod tests { DeployConfig { chain: ChainConfig { chain_id: 1234 }, contracts: ContractsConfig { - admin_proxy: Some(AdminProxyConfig { - address: None, - owner: address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), - }), + admin_proxy: None, permit2: Some(Permit2Config { address: None }), }, } } #[tokio::test] - async fn pipeline_deploys_both_contracts() { + async fn pipeline_deploys_permit2() { let mock = MockDeployer::new(1234); let tmp_state = tempfile::NamedTempFile::new().unwrap(); std::fs::remove_file(tmp_state.path()).unwrap(); @@ -400,15 +329,11 @@ mod tests { run(&cfg, &mock).await.unwrap(); let state = DeployState::load(tmp_state.path()).unwrap(); - assert_eq!( - state.contracts.admin_proxy.as_ref().unwrap().status, - ContractStatus::Verified - ); assert_eq!( state.contracts.permit2.as_ref().unwrap().status, ContractStatus::Verified ); - assert_eq!(mock.deploys.lock().unwrap().len(), 2); + assert_eq!(mock.deploys.lock().unwrap().len(), 1); } #[tokio::test] @@ -425,11 +350,11 @@ mod tests { // First run run(&cfg, &mock).await.unwrap(); - assert_eq!(mock.deploys.lock().unwrap().len(), 2); + assert_eq!(mock.deploys.lock().unwrap().len(), 1); - // Second run — should skip both + // Second run — should skip run(&cfg, &mock).await.unwrap(); - assert_eq!(mock.deploys.lock().unwrap().len(), 2); // no new deploys + assert_eq!(mock.deploys.lock().unwrap().len(), 1); // no new deploys } #[tokio::test] diff --git a/bin/ev-deployer/src/deploy/state.rs b/bin/ev-deployer/src/deploy/state.rs index 17759aa..87a6a63 100644 --- a/bin/ev-deployer/src/deploy/state.rs +++ b/bin/ev-deployer/src/deploy/state.rs @@ -27,22 +27,15 @@ pub(crate) struct DeployState { #[derive(Debug, Serialize, Deserialize, PartialEq)] pub(crate) struct AppliedIntent { pub chain_id: u64, - pub admin_proxy: Option, pub permit2: Option, } -#[derive(Debug, Serialize, Deserialize, PartialEq)] -pub(crate) struct AppliedAdminProxy { - pub owner: Address, -} - #[derive(Debug, Serialize, Deserialize, PartialEq)] pub(crate) struct AppliedPermit2 {} /// Per-contract deployment states. #[derive(Debug, Default, Serialize, Deserialize)] pub(crate) struct ContractStates { - pub admin_proxy: Option, pub permit2: Option, } @@ -112,22 +105,6 @@ impl DeployState { config.chain.chain_id ); - // If admin_proxy was in the original intent, its owner must not change - if let Some(ref original_ap) = current.admin_proxy { - if let Some(ref new_ap) = config.contracts.admin_proxy { - eyre::ensure!( - new_ap.owner == original_ap.owner, - "immutability violation: admin_proxy.owner changed from {} to {}", - original_ap.owner, - new_ap.owner - ); - } else { - eyre::bail!( - "immutability violation: admin_proxy was configured but is now missing" - ); - } - } - // If permit2 was in the original intent, it must still be present if current.permit2.is_some() { eyre::ensure!( @@ -144,11 +121,6 @@ impl AppliedIntent { fn from_config(config: &DeployConfig) -> Self { Self { chain_id: config.chain.chain_id, - admin_proxy: config - .contracts - .admin_proxy - .as_ref() - .map(|ap| AppliedAdminProxy { owner: ap.owner }), permit2: config.contracts.permit2.as_ref().map(|_| AppliedPermit2 {}), } } @@ -158,16 +130,12 @@ impl AppliedIntent { mod tests { use super::*; use crate::config::*; - use alloy_primitives::address; fn test_config() -> DeployConfig { DeployConfig { chain: ChainConfig { chain_id: 1234 }, contracts: ContractsConfig { - admin_proxy: Some(AdminProxyConfig { - address: None, - owner: address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), - }), + admin_proxy: None, permit2: Some(Permit2Config { address: None }), }, } @@ -184,7 +152,6 @@ mod tests { fn new_state_snapshots_intent() { let state = DeployState::new(&test_config()); assert_eq!(state.applied_intent.chain_id, 1234); - assert!(state.applied_intent.admin_proxy.is_some()); assert!(state.applied_intent.permit2.is_some()); } @@ -218,49 +185,32 @@ mod tests { } #[test] - fn immutability_rejects_owner_change() { - let mut changed = test_config(); - let state = DeployState::new(&changed); - changed.contracts.admin_proxy.as_mut().unwrap().owner = - address!("0000000000000000000000000000000000000001"); - let err = state - .validate_immutability(&changed) - .unwrap_err() - .to_string(); - assert!(err.contains("admin_proxy.owner changed"), "{err}"); - } - - #[test] - fn immutability_allows_adding_new_contract() { + fn immutability_allows_adding_permit2() { let config = DeployConfig { chain: ChainConfig { chain_id: 1234 }, contracts: ContractsConfig { - admin_proxy: Some(AdminProxyConfig { - address: None, - owner: address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"), - }), + admin_proxy: None, permit2: None, }, }; let state = DeployState::new(&config); - // Now add permit2 — this should be allowed let mut extended = config; extended.contracts.permit2 = Some(Permit2Config { address: None }); assert!(state.validate_immutability(&extended).is_ok()); } #[test] - fn immutability_rejects_removing_contract() { + fn immutability_rejects_removing_permit2() { let mut changed = test_config(); let state = DeployState::new(&changed); - changed.contracts.admin_proxy = None; + changed.contracts.permit2 = None; let err = state .validate_immutability(&changed) .unwrap_err() .to_string(); assert!( - err.contains("admin_proxy was configured but is now missing"), + err.contains("permit2 was configured but is now missing"), "{err}" ); } From 922af604558a160f0b4e89fbe07e6d8f72b850f0 Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Mon, 30 Mar 2026 20:20:53 +0200 Subject: [PATCH 13/18] fix(ev-deployer): use atomic writes for deploy state file Write to a .tmp file first, then rename into place. Prevents state file corruption if the process crashes mid-write. --- bin/ev-deployer/src/deploy/state.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/ev-deployer/src/deploy/state.rs b/bin/ev-deployer/src/deploy/state.rs index 87a6a63..ea55371 100644 --- a/bin/ev-deployer/src/deploy/state.rs +++ b/bin/ev-deployer/src/deploy/state.rs @@ -86,10 +86,12 @@ impl DeployState { Ok(state) } - /// Save state to a JSON file. + /// Save state to a JSON file atomically (write to tmp, then rename). pub(crate) fn save(&self, path: &Path) -> eyre::Result<()> { let json = serde_json::to_string_pretty(self)?; - std::fs::write(path, json)?; + let tmp = path.with_extension("tmp"); + std::fs::write(&tmp, &json)?; + std::fs::rename(&tmp, path)?; Ok(()) } From bb3522861e18049d3a674a776a805c13d25a742c Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Tue, 31 Mar 2026 12:08:27 +0200 Subject: [PATCH 14/18] feat(ev-deployer): add CLI flags to init command --- bin/ev-deployer/src/main.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/bin/ev-deployer/src/main.rs b/bin/ev-deployer/src/main.rs index d622e24..95eb3c4 100644 --- a/bin/ev-deployer/src/main.rs +++ b/bin/ev-deployer/src/main.rs @@ -6,6 +6,7 @@ mod deploy; mod genesis; mod output; +use alloy_primitives::Address; use clap::{Parser, Subcommand}; use std::path::PathBuf; @@ -22,11 +23,23 @@ struct Cli { #[derive(Subcommand)] enum Command { - /// Generate a starter config file with all supported contracts commented out. + /// Generate a starter config file with all supported contracts. Init { /// Write config to this file instead of stdout. #[arg(long)] output: Option, + + /// Set the chain ID (defaults to 0). + #[arg(long)] + chain_id: Option, + + /// Include Permit2 with its canonical address. + #[arg(long)] + permit2: bool, + + /// Include AdminProxy with the given owner address. + #[arg(long)] + admin_proxy_owner: Option
, }, /// Generate genesis alloc JSON from a deploy config. Genesis { @@ -140,7 +153,7 @@ fn main() -> eyre::Result<()> { .build()? .block_on(deploy::pipeline::run(&pipeline_cfg, &deployer))?; } - Command::Init { output } => { + Command::Init { output, .. } => { let template = include_str!("init_template.toml"); if let Some(ref out_path) = output { From 48a4d3998c6db1445c706ea5988725ee16ad592b Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Tue, 31 Mar 2026 12:10:38 +0200 Subject: [PATCH 15/18] feat(ev-deployer): add template builder with parameterized tests --- bin/ev-deployer/src/init.rs | 145 ++++++++++++++++++++++++++++++++++++ bin/ev-deployer/src/main.rs | 1 + 2 files changed, 146 insertions(+) create mode 100644 bin/ev-deployer/src/init.rs diff --git a/bin/ev-deployer/src/init.rs b/bin/ev-deployer/src/init.rs new file mode 100644 index 0000000..a45a598 --- /dev/null +++ b/bin/ev-deployer/src/init.rs @@ -0,0 +1,145 @@ +//! Dynamic config template generation for the `init` command. + +/// Parameters for generating the init template. +pub(crate) struct InitParams { + pub chain_id: u64, + pub permit2: bool, + pub admin_proxy_owner: Option, +} + +/// Generate a TOML config template based on the given parameters. +pub(crate) fn generate_template(params: &InitParams) -> String { + let mut out = String::new(); + + // Header + out.push_str("# EV Deployer configuration\n"); + out.push_str("# See: bin/ev-deployer/README.md\n"); + out.push_str("\n"); + + // Chain + out.push_str("[chain]\n"); + out.push_str("# The chain ID for the target network.\n"); + out.push_str(&format!("chain_id = {}\n", params.chain_id)); + + // Contracts section header + out.push_str("\n"); + out.push_str("# ── Contracts ────────────────────────────────────────────\n"); + out.push_str("# Uncomment and configure the contracts you want to deploy.\n"); + out.push_str("# The `address` field is required for `genesis` mode but\n"); + out.push_str("# ignored in `deploy` mode (addresses come from CREATE2).\n"); + + // AdminProxy + out.push_str("\n"); + if let Some(ref owner) = params.admin_proxy_owner { + out.push_str("# AdminProxy: transparent proxy with owner-based access control.\n"); + out.push_str("# The owner address is stored in slot 0.\n"); + out.push_str("[contracts.admin_proxy]\n"); + out.push_str("address = \"0x000000000000000000000000000000000000Ad00\"\n"); + out.push_str(&format!("owner = \"{owner}\"\n")); + } else { + out.push_str("# AdminProxy: transparent proxy with owner-based access control.\n"); + out.push_str("# The owner address is stored in slot 0.\n"); + out.push_str("# [contracts.admin_proxy]\n"); + out.push_str("# address = \"0x000000000000000000000000000000000000Ad00\"\n"); + out.push_str("# owner = \"0x...\"\n"); + } + + // Permit2 + out.push_str("\n"); + if params.permit2 { + out.push_str("# Permit2: Uniswap canonical token approval manager.\n"); + out.push_str("[contracts.permit2]\n"); + out.push_str("address = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\"\n"); + } else { + out.push_str("# Permit2: Uniswap canonical token approval manager.\n"); + out.push_str("# [contracts.permit2]\n"); + out.push_str("# address = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\"\n"); + } + + out +} + +#[cfg(test)] +mod tests { + use super::*; + + /// The static template that the old `init` used to emit. + const LEGACY_TEMPLATE: &str = include_str!("init_template.toml"); + + #[test] + fn default_params_match_legacy_template() { + let params = InitParams { + chain_id: 0, + permit2: false, + admin_proxy_owner: None, + }; + let output = generate_template(¶ms); + assert_eq!(output, LEGACY_TEMPLATE); + } + + #[test] + fn custom_chain_id() { + let params = InitParams { + chain_id: 42170, + permit2: false, + admin_proxy_owner: None, + }; + let output = generate_template(¶ms); + assert!(output.contains("chain_id = 42170"), "{output}"); + assert!(output.contains("# [contracts.permit2]"), "{output}"); + assert!(output.contains("# [contracts.admin_proxy]"), "{output}"); + } + + #[test] + fn permit2_enabled() { + let params = InitParams { + chain_id: 0, + permit2: true, + admin_proxy_owner: None, + }; + let output = generate_template(¶ms); + assert!(output.contains("[contracts.permit2]\n"), "{output}"); + assert!( + output.contains("address = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\""), + "{output}" + ); + assert!(output.contains("# [contracts.admin_proxy]"), "{output}"); + } + + #[test] + fn admin_proxy_with_owner() { + let params = InitParams { + chain_id: 0, + permit2: false, + admin_proxy_owner: Some( + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266".to_string(), + ), + }; + let output = generate_template(¶ms); + assert!(output.contains("[contracts.admin_proxy]\n"), "{output}"); + assert!( + output.contains("owner = \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\""), + "{output}" + ); + assert!(output.contains("# [contracts.permit2]"), "{output}"); + } + + #[test] + fn all_flags_combined() { + let params = InitParams { + chain_id: 1234, + permit2: true, + admin_proxy_owner: Some( + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266".to_string(), + ), + }; + let output = generate_template(¶ms); + assert!(output.contains("chain_id = 1234"), "{output}"); + assert!(output.contains("[contracts.permit2]\n"), "{output}"); + assert!(output.contains("[contracts.admin_proxy]\n"), "{output}"); + assert!( + output.contains("owner = \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\""), + "{output}" + ); + } +} diff --git a/bin/ev-deployer/src/main.rs b/bin/ev-deployer/src/main.rs index 95eb3c4..69ade86 100644 --- a/bin/ev-deployer/src/main.rs +++ b/bin/ev-deployer/src/main.rs @@ -4,6 +4,7 @@ mod config; mod contracts; mod deploy; mod genesis; +mod init; mod output; use alloy_primitives::Address; From 9771899c0dcf11f614c37525e7a3a85b48531ba3 Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Tue, 31 Mar 2026 12:18:16 +0200 Subject: [PATCH 16/18] feat(ev-deployer): wire parameterized init into CLI --- bin/ev-deployer/src/main.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/bin/ev-deployer/src/main.rs b/bin/ev-deployer/src/main.rs index 69ade86..08bf7a3 100644 --- a/bin/ev-deployer/src/main.rs +++ b/bin/ev-deployer/src/main.rs @@ -154,11 +154,21 @@ fn main() -> eyre::Result<()> { .build()? .block_on(deploy::pipeline::run(&pipeline_cfg, &deployer))?; } - Command::Init { output, .. } => { - let template = include_str!("init_template.toml"); + Command::Init { + output, + chain_id, + permit2, + admin_proxy_owner, + } => { + let params = init::InitParams { + chain_id: chain_id.unwrap_or(0), + permit2, + admin_proxy_owner: admin_proxy_owner.map(|a| format!("{a}")), + }; + let template = init::generate_template(¶ms); if let Some(ref out_path) = output { - std::fs::write(out_path, template)?; + std::fs::write(out_path, &template)?; eprintln!("Wrote config to {}", out_path.display()); } else { print!("{template}"); From 9c2fcb6758c58761cb5e5a8d18a537567b9347ef Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Tue, 31 Mar 2026 12:19:53 +0200 Subject: [PATCH 17/18] docs(ev-deployer): rewrite README as comprehensive user guide --- bin/ev-deployer/README.md | 174 ++++++++++++++++++++++++++------------ 1 file changed, 118 insertions(+), 56 deletions(-) diff --git a/bin/ev-deployer/README.md b/bin/ev-deployer/README.md index 4aad297..f38e186 100644 --- a/bin/ev-deployer/README.md +++ b/bin/ev-deployer/README.md @@ -1,6 +1,34 @@ # EV Deployer -CLI tool for generating genesis alloc entries for ev-reth contracts. It reads a declarative TOML config and produces the JSON needed to embed contracts into a chain's genesis state. +CLI tool for deploying ev-reth contracts. It reads a declarative TOML config and either embeds contracts into a chain's genesis state or deploys them to a live chain via CREATE2. + +## Modes of Operation + +EV Deployer has two deployment modes: + +| Mode | When to use | What it does | +|------|-------------|-------------| +| **genesis** | Before the chain starts | Produces JSON alloc entries to embed contracts into the genesis state. No RPC needed. | +| **deploy** | On a running chain | Deploys contracts via CREATE2 through the deterministic deployer. Requires RPC + signer. | + +Both modes read the same TOML config. The `address` field in each contract section is used by `genesis` to place the contract at that exact address. In `deploy` mode, addresses are computed deterministically via CREATE2 and the config `address` is ignored. + +## Quick Start + +```bash +# 1. Generate a config pre-populated for your chain +ev-deployer init --chain-id 42170 --permit2 --output deploy.toml + +# 2a. Genesis mode: embed into genesis state +ev-deployer genesis --config deploy.toml --merge-into genesis.json --output genesis-out.json + +# 2b. Deploy mode: deploy to a live chain +ev-deployer deploy \ + --config deploy.toml \ + --rpc-url http://localhost:8545 \ + --private-key 0x... \ + --state deploy-state.json +``` ## Building @@ -10,98 +38,132 @@ just build-deployer The binary is output to `target/release/ev-deployer`. -## Configuration +## Commands -EV Deployer uses a TOML config file to define what contracts to include and how to configure them. See [`examples/devnet.toml`](examples/devnet.toml) for a complete example. +### `init` -### Config reference +Generate a starter config file. -#### `[chain]` +```bash +# Bare template (all contracts commented out) +ev-deployer init + +# Pre-populated with chain ID and Permit2 +ev-deployer init --chain-id 42170 --permit2 + +# Full config with all contracts +ev-deployer init \ + --chain-id 42170 \ + --permit2 \ + --admin-proxy-owner 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 \ + --output deploy.toml +``` -| Field | Type | Description | -|------------|------|-------------| -| `chain_id` | u64 | Chain ID | +| Flag | Description | +|------|-------------| +| `--output ` | Write to file instead of stdout | +| `--chain-id ` | Set the chain ID (defaults to 0) | +| `--permit2` | Enable Permit2 with its canonical address | +| `--admin-proxy-owner ` | Enable AdminProxy with the given owner | -#### `[contracts.admin_proxy]` +### `genesis` -| Field | Type | Description | -|-----------|---------|---------------------------| -| `address` | address | Address to deploy at | -| `owner` | address | Owner (must not be zero) | +Generate genesis alloc JSON from a config. -#### `[contracts.permit2]` +```bash +# Print alloc to stdout +ev-deployer genesis --config deploy.toml -| Field | Type | Description | -|-----------|---------|----------------------------------------------------------| -| `address` | address | Address to deploy at (canonical: `0x000000000022D473030F116dDEE9F6B43aC78BA3`) | +# Write to file +ev-deployer genesis --config deploy.toml --output alloc.json -## Usage +# Merge into an existing genesis file +ev-deployer genesis --config deploy.toml --merge-into genesis.json --output genesis-out.json -### Generate a starter config +# Overwrite existing addresses when merging +ev-deployer genesis --config deploy.toml --merge-into genesis.json --output genesis-out.json --force -```bash -ev-deployer init --output deploy.toml +# Also export an address manifest +ev-deployer genesis --config deploy.toml --addresses-out addresses.json ``` -This creates a TOML config template with all supported contracts commented out and documented. +In genesis mode, every configured contract must have an `address` field. -### Generate genesis alloc +### `deploy` -Print alloc JSON to stdout: +Deploy contracts to a live chain via CREATE2. ```bash -ev-deployer genesis --config deploy.toml +ev-deployer deploy \ + --config deploy.toml \ + --rpc-url http://localhost:8545 \ + --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ + --state deploy-state.json \ + --addresses-out addresses.json ``` -Write to a file: +| Flag | Env var | Description | +|------|---------|-------------| +| `--config ` | | Path to the TOML config | +| `--rpc-url ` | `EV_DEPLOYER_RPC_URL` | RPC endpoint of the target chain | +| `--private-key ` | `EV_DEPLOYER_PRIVATE_KEY` | Hex-encoded private key for signing | +| `--state ` | | Path to the state file (created if absent) | +| `--addresses-out ` | | Write a JSON address manifest | -```bash -ev-deployer genesis --config deploy.toml --output alloc.json -``` +The deploy pipeline: -### Merge into an existing genesis file +1. Connects to the RPC and verifies the chain ID matches the config. +2. Checks that the deterministic deployer (`0x4e59b44847b379578588920ca78fbf26c0b4956c`) exists on-chain. +3. Deploys each configured contract via CREATE2. +4. Verifies that the on-chain bytecode matches the expected bytecode (including patched immutables). -Insert the generated entries into an existing `genesis.json`. The merged result is written to `--output` (or stdout if `--output` is omitted): +The `address` field in the config is **ignored** in deploy mode — addresses come from the CREATE2 computation. -```bash -ev-deployer genesis --config deploy.toml --merge-into genesis.json --output genesis-out.json -``` +#### State file and resumability -If an address already exists in the genesis, the command fails. Use `--force` to overwrite: +The `--state` file tracks deployment progress. On first run it generates a random CREATE2 salt and records which contracts have been deployed. If the process is interrupted, re-running with the same state file resumes where it left off. -```bash -ev-deployer genesis --config deploy.toml --merge-into genesis.json --output genesis-out.json --force -``` +Immutability rules protect against accidental misconfiguration on resume: + +- The `chain_id` cannot change between runs. +- A contract that was configured in the original run cannot be removed. +- New contracts can be added to subsequent runs. -### Export address manifest +### `compute-address` -Write a JSON mapping of contract names to their configured addresses: +Look up the configured address for a contract. ```bash -ev-deployer genesis --config deploy.toml --addresses-out addresses.json +ev-deployer compute-address --config deploy.toml --contract permit2 ``` -Output: +## Config Reference -```json -{ - "admin_proxy": "0x000000000000000000000000000000000000Ad00", - "permit2": "0x000000000022D473030F116dDEE9F6B43aC78BA3" -} -``` +### `[chain]` -### Look up a contract address +| Field | Type | Description | +|-------|------|-------------| +| `chain_id` | u64 | Chain ID | -```bash -ev-deployer compute-address --config deploy.toml --contract admin_proxy -``` +### `[contracts.admin_proxy]` + +| Field | Type | Description | +|-------|------|-------------| +| `address` | address | Address to deploy at (required for genesis, ignored for deploy) | +| `owner` | address | Owner address (must not be zero) | + +### `[contracts.permit2]` + +| Field | Type | Description | +|-------|------|-------------| +| `address` | address | Address to deploy at (canonical: `0x000000000022D473030F116dDEE9F6B43aC78BA3`). Required for genesis, ignored for deploy. | ## Contracts -| Contract | Description | -|---------------|----------------------------------------------------| -| `admin_proxy` | Proxy contract with owner-based access control | -| `permit2` | Uniswap canonical token approval manager | +| Contract | Description | +|----------|-------------| +| `admin_proxy` | Transparent proxy with owner-based access control | +| `permit2` | Uniswap canonical token approval manager (same address on all chains) | Runtime bytecodes are embedded in the binary — no external toolchain is needed at deploy time. From 71afcec7a636a65089b3fb9ed2b09f8e669c48c4 Mon Sep 17 00:00:00 2001 From: Randy Grok Date: Tue, 31 Mar 2026 13:04:22 +0200 Subject: [PATCH 18/18] fix(ev-deployer): address clippy lints and rustfmt in init module --- bin/ev-deployer/src/init.rs | 25 +++++++++---------------- bin/ev-deployer/src/main.rs | 4 ++-- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/bin/ev-deployer/src/init.rs b/bin/ev-deployer/src/init.rs index a45a598..f33509a 100644 --- a/bin/ev-deployer/src/init.rs +++ b/bin/ev-deployer/src/init.rs @@ -14,7 +14,7 @@ pub(crate) fn generate_template(params: &InitParams) -> String { // Header out.push_str("# EV Deployer configuration\n"); out.push_str("# See: bin/ev-deployer/README.md\n"); - out.push_str("\n"); + out.push('\n'); // Chain out.push_str("[chain]\n"); @@ -22,36 +22,33 @@ pub(crate) fn generate_template(params: &InitParams) -> String { out.push_str(&format!("chain_id = {}\n", params.chain_id)); // Contracts section header - out.push_str("\n"); + out.push('\n'); out.push_str("# ── Contracts ────────────────────────────────────────────\n"); out.push_str("# Uncomment and configure the contracts you want to deploy.\n"); out.push_str("# The `address` field is required for `genesis` mode but\n"); out.push_str("# ignored in `deploy` mode (addresses come from CREATE2).\n"); // AdminProxy - out.push_str("\n"); + out.push('\n'); + out.push_str("# AdminProxy: transparent proxy with owner-based access control.\n"); + out.push_str("# The owner address is stored in slot 0.\n"); if let Some(ref owner) = params.admin_proxy_owner { - out.push_str("# AdminProxy: transparent proxy with owner-based access control.\n"); - out.push_str("# The owner address is stored in slot 0.\n"); out.push_str("[contracts.admin_proxy]\n"); out.push_str("address = \"0x000000000000000000000000000000000000Ad00\"\n"); out.push_str(&format!("owner = \"{owner}\"\n")); } else { - out.push_str("# AdminProxy: transparent proxy with owner-based access control.\n"); - out.push_str("# The owner address is stored in slot 0.\n"); out.push_str("# [contracts.admin_proxy]\n"); out.push_str("# address = \"0x000000000000000000000000000000000000Ad00\"\n"); out.push_str("# owner = \"0x...\"\n"); } // Permit2 - out.push_str("\n"); + out.push('\n'); + out.push_str("# Permit2: Uniswap canonical token approval manager.\n"); if params.permit2 { - out.push_str("# Permit2: Uniswap canonical token approval manager.\n"); out.push_str("[contracts.permit2]\n"); out.push_str("address = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\"\n"); } else { - out.push_str("# Permit2: Uniswap canonical token approval manager.\n"); out.push_str("# [contracts.permit2]\n"); out.push_str("# address = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\"\n"); } @@ -111,9 +108,7 @@ mod tests { let params = InitParams { chain_id: 0, permit2: false, - admin_proxy_owner: Some( - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266".to_string(), - ), + admin_proxy_owner: Some("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266".to_string()), }; let output = generate_template(¶ms); assert!(output.contains("[contracts.admin_proxy]\n"), "{output}"); @@ -129,9 +124,7 @@ mod tests { let params = InitParams { chain_id: 1234, permit2: true, - admin_proxy_owner: Some( - "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266".to_string(), - ), + admin_proxy_owner: Some("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266".to_string()), }; let output = generate_template(¶ms); assert!(output.contains("chain_id = 1234"), "{output}"); diff --git a/bin/ev-deployer/src/main.rs b/bin/ev-deployer/src/main.rs index 08bf7a3..b51dc62 100644 --- a/bin/ev-deployer/src/main.rs +++ b/bin/ev-deployer/src/main.rs @@ -34,11 +34,11 @@ enum Command { #[arg(long)] chain_id: Option, - /// Include Permit2 with its canonical address. + /// Include `Permit2` with its canonical address. #[arg(long)] permit2: bool, - /// Include AdminProxy with the given owner address. + /// Include `AdminProxy` with the given owner address. #[arg(long)] admin_proxy_owner: Option
, },