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", ] diff --git a/bin/ev-deployer/Cargo.toml b/bin/ev-deployer/Cargo.toml index b80d21a..ff9eae7 100644 --- a/bin/ev-deployer/Cargo.toml +++ b/bin/ev-deployer/Cargo.toml @@ -10,11 +10,17 @@ 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 } toml = "0.8" eyre = { workspace = true } +rand = { workspace = true } [dev-dependencies] tempfile = { workspace = true } 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. 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..defa9c2 100644 --- a/bin/ev-deployer/src/contracts/admin_proxy.rs +++ b/bin/ev-deployer/src/contracts/admin_proxy.rs @@ -6,10 +6,10 @@ 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 +17,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 +32,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..eabbbe7 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,51 @@ 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"); + +/// `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`. -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 +93,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 +116,7 @@ mod tests { fn test_config() -> Permit2Config { Permit2Config { - address: address!("000000000022D473030F116dDEE9F6B43aC78BA3"), + address: Some(address!("000000000022D473030F116dDEE9F6B43aC78BA3")), } } @@ -138,7 +150,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 +175,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/deploy/create2.rs b/bin/ev-deployer/src/deploy/create2.rs new file mode 100644 index 0000000..cb3b3cf --- /dev/null +++ b/bin/ev-deployer/src/deploy/create2.rs @@ -0,0 +1,75 @@ +//! CREATE2 address computation. + +use alloy_primitives::{keccak256, Address, Bytes, B256}; + +/// The deterministic deployer factory address (Nick's factory). +/// See: +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/deployer.rs b/bin/ev-deployer/src/deploy/deployer.rs new file mode 100644 index 0000000..a673e2a --- /dev/null +++ b/bin/ev-deployer/src/deploy/deployer.rs @@ -0,0 +1,83 @@ +//! `ChainDeployer` trait and `LiveDeployer` implementation. + +use crate::deploy::create2::{build_factory_calldata, DETERMINISTIC_DEPLOYER}; +use alloy::{ + network::EthereumWallet, + 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 new file mode 100644 index 0000000..7990f24 --- /dev/null +++ b/bin/ev-deployer/src/deploy/mod.rs @@ -0,0 +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..9db2ead --- /dev/null +++ b/bin/ev-deployer/src/deploy/pipeline.rs @@ -0,0 +1,393 @@ +//! Deploy pipeline: orchestrates the full deployment flow. + +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}; + +/// 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/4] 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/4] 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 Permit2 ── + if let Some(ref p2_config) = pipeline_cfg.config.contracts.permit2 { + eprintln!("[3/4] Deploying Permit2..."); + + if p2_config.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, + &DeployContractParams { + name: "permit2", + address, + salt, + initcode: &initcode, + expected_runtime: &expected_runtime, + state_path: &pipeline_cfg.state_path, + }, + ) + .await?; + } else { + eprintln!("[3/4] Permit2 not configured, skipping"); + } + + // ── 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"); + + // ── 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(()) +} + +/// 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, + 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) { + 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: *address, + deploy_tx: None, + }, + ); + state.save(state_path)?; + return Ok(()); + } + 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: *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.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 { + 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) { + 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.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::*, deploy::deployer::TxReceipt}; + use alloy_primitives::Bytes; + use async_trait::async_trait; + use std::{collections::HashMap, 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); + + 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), + success: true, + }) + } + } + + fn test_config() -> DeployConfig { + DeployConfig { + chain: ChainConfig { chain_id: 1234 }, + contracts: ContractsConfig { + admin_proxy: None, + permit2: Some(Permit2Config { address: None }), + }, + } + } + + #[tokio::test] + 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(); + + 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.permit2.as_ref().unwrap().status, + ContractStatus::Verified + ); + assert_eq!(mock.deploys.lock().unwrap().len(), 1); + } + + #[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(), 1); + + // Second run — should skip + run(&cfg, &mock).await.unwrap(); + assert_eq!(mock.deploys.lock().unwrap().len(), 1); // 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}"); + } +} diff --git a/bin/ev-deployer/src/deploy/state.rs b/bin/ev-deployer/src/deploy/state.rs new file mode 100644 index 0000000..ea55371 --- /dev/null +++ b/bin/ev-deployer/src/deploy/state.rs @@ -0,0 +1,225 @@ +//! 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 permit2: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub(crate) struct AppliedPermit2 {} + +/// Per-contract deployment states. +#[derive(Debug, Default, Serialize, Deserialize)] +pub(crate) struct ContractStates { + 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 atomically (write to tmp, then rename). + pub(crate) fn save(&self, path: &Path) -> eyre::Result<()> { + let json = serde_json::to_string_pretty(self)?; + let tmp = path.with_extension("tmp"); + std::fs::write(&tmp, &json)?; + std::fs::rename(&tmp, path)?; + 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 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, + permit2: config.contracts.permit2.as_ref().map(|_| AppliedPermit2 {}), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::config::*; + + fn test_config() -> DeployConfig { + DeployConfig { + chain: ChainConfig { chain_id: 1234 }, + contracts: ContractsConfig { + admin_proxy: None, + 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.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 mut changed = test_config(); + let state = DeployState::new(&changed); + 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_allows_adding_permit2() { + let config = DeployConfig { + chain: ChainConfig { chain_id: 1234 }, + contracts: ContractsConfig { + admin_proxy: None, + permit2: None, + }, + }; + let state = DeployState::new(&config); + + let mut extended = config; + extended.contracts.permit2 = Some(Permit2Config { address: None }); + assert!(state.validate_immutability(&extended).is_ok()); + } + + #[test] + fn immutability_rejects_removing_permit2() { + let mut changed = test_config(); + let state = DeployState::new(&changed); + changed.contracts.permit2 = None; + let err = state + .validate_immutability(&changed) + .unwrap_err() + .to_string(); + assert!( + err.contains("permit2 was configured but is now missing"), + "{err}" + ); + } + + #[test] + fn contract_status_ordering() { + assert!(ContractStatus::Pending < ContractStatus::Deployed); + assert!(ContractStatus::Deployed < ContractStatus::Verified); + } +} 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/init.rs b/bin/ev-deployer/src/init.rs new file mode 100644 index 0000000..f33509a --- /dev/null +++ b/bin/ev-deployer/src/init.rs @@ -0,0 +1,138 @@ +//! 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('\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('\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('\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("[contracts.admin_proxy]\n"); + out.push_str("address = \"0x000000000000000000000000000000000000Ad00\"\n"); + out.push_str(&format!("owner = \"{owner}\"\n")); + } else { + out.push_str("# [contracts.admin_proxy]\n"); + out.push_str("# address = \"0x000000000000000000000000000000000000Ad00\"\n"); + out.push_str("# owner = \"0x...\"\n"); + } + + // Permit2 + out.push('\n'); + out.push_str("# Permit2: Uniswap canonical token approval manager.\n"); + if params.permit2 { + out.push_str("[contracts.permit2]\n"); + out.push_str("address = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\"\n"); + } else { + 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/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. diff --git a/bin/ev-deployer/src/main.rs b/bin/ev-deployer/src/main.rs index 5d87ae9..b51dc62 100644 --- a/bin/ev-deployer/src/main.rs +++ b/bin/ev-deployer/src/main.rs @@ -1,18 +1,21 @@ -//! 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; +mod deploy; mod genesis; +mod init; mod output; +use alloy_primitives::Address; 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)] @@ -21,11 +24,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 { @@ -49,6 +64,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. @@ -73,6 +110,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)? @@ -96,11 +134,41 @@ fn main() -> eyre::Result<()> { eprintln!("Wrote address manifest to {}", addr_path.display()); } } - Command::Init { output } => { - let template = include_str!("init_template.toml"); + 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, + 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}"); @@ -117,14 +185,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..8053180 100644 --- a/bin/ev-deployer/src/output.rs +++ b/bin/ev-deployer/src/output.rs @@ -8,17 +8,18 @@ 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)