Skip to content

feat(ev-deployer): part 1 - add ev-deployer CLI for genesis contract allocation#167

Open
randygrok wants to merge 20 commits intomainfrom
ev-deployer-part1-core
Open

feat(ev-deployer): part 1 - add ev-deployer CLI for genesis contract allocation#167
randygrok wants to merge 20 commits intomainfrom
ev-deployer-part1-core

Conversation

@randygrok
Copy link
Contributor

@randygrok randygrok commented Mar 13, 2026

Part of #119

Implements Part 1 (Core) of EV Deployer — a CLI tool for generating genesis alloc entries for ev-reth contracts via declarative TOML configuration.

The tool reads a TOML config file, encodes contract bytecode and storage state, and generates Ethereum-compatible genesis alloc JSON. Supports merging into existing genesis files with collision detection.

CLI commands

Command Description
init Generate a starter TOML config with all supported contracts commented out and documented
genesis Build genesis alloc JSON from a deploy config
compute-address Look up the configured address for a contract

genesis flags

  • --config — path to deploy TOML
  • --output — write JSON to file (stdout if omitted)
  • --merge-into — merge alloc entries into an existing genesis JSON
  • --force — allow overwriting existing addresses when merging
  • --addresses-out — export a JSON manifest of contract name → address

Contracts supported

Contract Description
admin_proxy Transparent proxy with owner-based access control (bytecode + owner in slot 0)

What's included

  • CLI framework with three subcommands (init, genesis, compute-address)
  • TOML config parsing and validation ([chain] required, [contracts] optional)
  • Genesis alloc builder with merge support and collision detection
  • Address manifest output
  • AdminProxy contract encoding (bytecode + owner storage)
  • E2E test that boots ev-reth with the generated genesis
  • CI workflow for unit and e2e tests

FeeVault and other contracts will be added in follow-up PRs.

@randygrok randygrok requested a review from a team as a code owner March 13, 2026 17:48
@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new ev-deployer CLI crate and associated tooling: TOML config parsing, contract bytecode/storage encoding, genesis alloc JSON generation and merging, address manifest output, tests (unit + e2e), CI workflow, and build/test recipes.

Changes

Cohort / File(s) Summary
CI / Workflows
.github/workflows/ev_deployer.yml
New GitHub Actions workflow with jobs: verify-bytecodes, unit-tests, and e2e-genesis; triggers on push, pull_request, and workflow_dispatch with path filters.
Workspace
Cargo.toml
Added bin/ev-deployer to workspace members.
ev-deployer manifest
bin/ev-deployer/Cargo.toml
New crate manifest declaring dependencies and dev-deps for the CLI.
CLI entrypoint
bin/ev-deployer/src/main.rs
New binary with Genesis and ComputeAddress subcommands, CLI parsing, file I/O, and output behavior (--output, --merge-into, --addresses-out).
Config parsing & validation
bin/ev-deployer/src/config.rs
TOML-deserializable config types (DeployConfig, ChainConfig, ContractsConfig, AdminProxyConfig) and DeployConfig::load with validation (reject zero owner).
Genesis construction & merging
bin/ev-deployer/src/genesis.rs
Builds alloc JSON from contracts, formats code/storage, merges into existing genesis with collision detection and optional --force.
Contracts scaffolding
bin/ev-deployer/src/contracts/mod.rs, bin/ev-deployer/src/contracts/admin_proxy.rs
GenesisContract struct, admin_proxy module with embedded runtime bytecode and build that sets address, code, and slot-0 owner encoding; unit tests included.
Output manifest
bin/ev-deployer/src/output.rs
build_manifest to emit JSON mapping of configured contract names → addresses.
Documentation & examples
bin/ev-deployer/README.md, bin/ev-deployer/examples/devnet.toml
README describing TOML schema and CLI usage; example devnet config with chain_id and contracts.admin_proxy.
End-to-end test script
bin/ev-deployer/tests/e2e_genesis.sh
E2E script: builds binaries, generates merged genesis, boots ev-reth, polls JSON-RPC, verifies bytecode and storage value.
Build / Foundry
justfile, contracts/foundry.toml
Added build-deployer and test-deployer recipes; Foundry profile settings (solc_version, cbor_metadata, bytecode_hash).

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer (runs CLI)
  participant FS as Filesystem (config / genesis.json)
  participant CLI as ev-deployer
  participant Node as ev-reth (RPC)
  rect rgba(200,200,255,0.5)
    Dev->>CLI: run `ev-deployer genesis --merge-into base.json --config devnet.toml`
    CLI->>FS: read `devnet.toml`
    CLI->>CLI: build contract GenesisContract (address, code, storage)
    CLI->>FS: read `base.json`
    CLI->>FS: merge alloc entries (check collisions, apply --force if set)
    CLI->>FS: write merged genesis.json
  end
  rect rgba(200,255,200,0.5)
    Dev->>Node: start `ev-reth --genesis merged.json`
    Node->>Dev: exposes JSON-RPC
    Dev->>Node: curl eth_getCode / eth_getStorageAt
    Node->>Dev: return code and storage => verify matches expected
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • damiannolan
  • chatton
  • tac0turtle

Poem

🐰 From TOML burrowed deep I hop and write,
Genesis keys gleam in the moonlit byte,
Contracts tucked in JSON's gentle nest,
The rabbit cheers: "Deployments now rest!" ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description provides comprehensive details about the implementation, including feature overview, CLI commands, supported flags, contracts, and scope. However, it diverges from the repository's template structure. Confirm whether the PR description fully aligns with template expectations or if the custom format is acceptable for this repository's standards.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding the ev-deployer CLI tool for genesis contract allocation, which matches the primary objective of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 86.67% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ev-deployer-part1-core

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link

claude bot commented Mar 13, 2026

Claude finished @randygrok's task —— View job


Code Review for ev-deployer Part 1

I've completed a comprehensive review of this new ev-deployer CLI implementation. Overall, this is a well-structured tool with good separation of concerns, appropriate error handling, and solid testing. Here are my findings:

Strengths

Architecture & Code Quality

  • Clean modular design: Well-organized modules (config, genesis, contracts, output) with clear responsibilities
  • Strong type safety: Good use of alloy_primitives types (Address, B256, Bytes) for blockchain-specific data
  • Appropriate error handling: Consistent use of eyre::Result with descriptive error messages
  • CLI design: Well-structured clap-based interface with logical subcommands and clear help text

Configuration & Validation

  • Robust TOML parsing: Proper serde deserialization with sensible defaults using #[serde(default)]
  • Input validation: Validates critical values like non-zero owner addresses during config loading
  • Good test coverage: Comprehensive config parsing tests including edge cases (zero owner, missing sections)

Genesis Building Logic

  • Smart address normalization: normalize_addr() function properly handles different address formats (with/without 0x, mixed case)
  • Collision detection: Proper detection of address conflicts with clear error messages and --force override option
  • Correct storage encoding: Proper formatting of storage slots and values for Ethereum compatibility

Contract Implementation

  • Embedded bytecode approach: Smart choice to embed compiled bytecode, eliminating external toolchain dependencies
  • Validation with forge: Excellent ignored test that verifies hardcoded bytecode matches source using forge
  • Proper storage layout: Correctly encodes AdminProxy owner in slot 0 with proper padding

⚠️ Issues & Concerns

Security & Validation

  1. Missing zero address validation for deployment target (config.rs:52-60):

    // Should also validate admin_proxy.address is non-zero
    eyre::ensure!(!ap.address.is_zero(), "admin_proxy.address must not be the zero address");
  2. Hardcoded bytecode security: While the forge verification test is good, consider adding build-time verification or checksum validation for production use.

Error Handling & Robustness

  1. Panic potential in admin_proxy test (admin_proxy.rs:68-72):

    • The test uses .trim_start_matches("0x") which is safer than .strip_prefix("0x").unwrap() - good fix already applied
    • However, still has String::from_utf8(output.stdout).unwrap() which could panic on invalid UTF-8
  2. CLI behavior inconsistency (main.rs:85-90):

    • When using --merge-into without --output, the merged result goes to stdout instead of back to the original file
    • This could be confusing for users expecting in-place modification

Performance & Efficiency

  1. String manipulations: Some inefficient string operations, though not critical for this use case
  2. Memory usage: Genesis JSON is loaded entirely into memory, but reasonable for typical genesis file sizes

Testing & Validation

  1. Limited error path testing: The genesis merge collision tests are good, but could use more error scenarios
  2. E2E test could be more robust: The bash script uses simple grep for validation instead of proper JSON parsing

🔧 Specific Recommendations

High Priority

  1. Add address validation: Validate that contract deployment addresses are non-zero in config.rs
  2. Fix CLI merge behavior: When --merge-into is used without --output, consider writing back to the original file
  3. Improve error handling: Replace remaining .unwrap() calls in tests with proper error handling

Medium Priority

  1. Enhanced collision detection: Consider validating that different contract types don't share addresses
  2. Better E2E validation: Replace grep-based checks with proper JSON parsing in the bash test
  3. Documentation: Add more inline documentation for complex functions like merge_into()

Low Priority

  1. Performance optimizations: Stream JSON processing for very large genesis files (if needed in future)
  2. Additional validation: Consider validating chain_id against known networks

📊 Test Coverage Assessment

Excellent coverage overall:

  • ✅ Config parsing and validation (comprehensive)
  • ✅ Genesis building and address formatting (good)
  • ✅ Contract bytecode verification (excellent with forge)
  • ✅ Merge collision detection (good edge cases)
  • ✅ E2E test with real ev-reth node (excellent)
  • ⚠️ Error path coverage could be expanded
  • ⚠️ CLI edge cases could use more testing

🔒 Security Assessment

Generally secure with minor concerns:

  • ✅ No SQL injection or file traversal risks
  • ✅ Proper input validation for critical fields
  • ✅ Safe handling of user-provided addresses and config
  • ⚠️ Embedded bytecode should have runtime verification in production
  • ⚠️ Consider validating config file permissions

🚀 Performance & Scalability

Well-suited for intended use:

  • ✅ Efficient for typical genesis file sizes (< 10MB)
  • ✅ Good error handling prevents resource leaks
  • ⚠️ Memory usage grows with genesis size (not critical for current use)
  • ✅ CLI startup time is fast

📋 Overall Assessment

This is a high-quality implementation that demonstrates good software engineering practices:

  • Clean, readable, and maintainable code structure
  • Appropriate use of Rust's type system and error handling
  • Comprehensive testing including E2E validation
  • Good documentation and user experience
  • Follows established patterns from the broader codebase

The identified issues are mostly minor and don't detract from the overall quality. This is suitable for production use with the recommended fixes applied.

Recommendation: ✅ APPROVE with minor fixes for the validation and CLI behavior issues.


@randygrok randygrok marked this pull request as draft March 13, 2026 17:48
@randygrok randygrok changed the title feat: add ev-deployer CLI for genesis contract allocation feat(ev-deployer): add ev-deployer CLI for genesis contract allocation Mar 18, 2026
@randygrok randygrok changed the title feat(ev-deployer): add ev-deployer CLI for genesis contract allocation feat(ev-deployer): part 1 - add ev-deployer CLI for genesis contract allocation Mar 18, 2026
@randygrok randygrok marked this pull request as ready for review March 19, 2026 09:48
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/ev_deployer.yml:
- Around line 6-13: The pull_request path filters in ev_deployer.yml only
include 'contracts/src/**', 'contracts/foundry.toml', and 'bin/ev-deployer/**',
so edits to root Cargo.toml, Cargo.lock, or the workflow itself won't trigger EV
Deployer CI and can break cargo test -p ev-deployer; update the
pull_request.paths block (the pull_request.paths entry in
.github/workflows/ev_deployer.yml) to also include the root-level files like
'Cargo.toml', 'Cargo.lock', and the workflow file (e.g.
'.github/workflows/ev_deployer.yml') so changes to those files will trigger the
workflow.

In `@bin/ev-deployer/README.md`:
- Around line 86-90: The README's description of the merge behavior is
misleading: update the text around the ev-deployer genesis command (referencing
the --merge-into and --output flags) to remove the phrase "modifies the `alloc`
field in-place" and explicitly state that the CLI does not mutate the original
file but writes the merged result to the path provided by --output (or to stdout
if --output is omitted); ensure the example command and accompanying sentence
clearly say the original genesis.json is unchanged and the merged output is
written to genesis-out.json (or stdout).

In `@bin/ev-deployer/src/config.rs`:
- Around line 83-101: The validate() method currently doesn't ensure contract
addresses are unique, allowing admin_proxy.address == fee_vault.address which
later causes silent alloc overwrites; add a check in validate() that if both
self.contracts.admin_proxy and self.contracts.fee_vault are Some, their .address
fields must not be equal and fail fast (use eyre::ensure or eyre::bail) with a
clear error like "admin_proxy.address must not equal fee_vault.address"; update
the validate() function to perform this uniqueness assertion alongside the
existing owner and bridge_share_bps checks.

In `@bin/ev-deployer/src/contracts/admin_proxy.rs`:
- Around line 68-73: The current normalization of forge output (building
forge_hex from output.stdout) uses unwraps and will panic on invalid UTF-8 or if
the "0x" prefix is missing; change it to handle errors safely by first
converting output.stdout with String::from_utf8 and propagating or logging the
error instead of unwrap, then perform trimming and lowercase on the resulting
string and remove a leading "0x" non-panically (e.g., use
strip_prefix("0x").unwrap_or(&s) or check starts_with and slice) to produce
forge_hex; update the code that assigns forge_hex (the variable constructed from
output.stdout) to return a Result or fallback value rather than panicking.

In `@bin/ev-deployer/src/contracts/fee_vault.rs`:
- Around line 171-176: The current normalization of forge output into forge_hex
uses multiple unwraps and can panic if the output is not valid UTF-8 or if the
"0x" prefix is missing; change it to a tolerant normalization that avoids
unwraps by using String::from_utf8_lossy on output.stdout and
trim_start_matches("0x") instead of strip_prefix/unwrap, e.g. build forge_hex
from
String::from_utf8_lossy(&output.stdout).trim().trim_start_matches("0x").to_lowercase()
so it safely handles missing "0x" and invalid UTF-8.

In `@bin/ev-deployer/src/main.rs`:
- Around line 71-75: When --merge-into is provided but no explicit --output is
given, the merged genesis currently only goes to stdout; change the control flow
so that when merge_into is Some(genesis_path) and output is None you persist the
merged result back to genesis_path. Concretely, after calling
genesis::merge_into(&cfg, genesis_path, force) (or using the merged value from
genesis::build_alloc when merging), write the resulting genesis bytes/string to
the same genesis_path (or call an existing genesis write helper) instead of only
printing to stdout; update the branch that handles merge_into (and the similar
branch around lines 79–84) to perform that write when output is unspecified.

In `@bin/ev-deployer/tests/e2e_genesis.sh`:
- Around line 35-38: The curl RPC calls that post JSON-RPC using RPC_URL with
variables method and params are currently blocking; update both curl invocations
(the ones that build the JSON payload with "$RPC_URL" and -d
"{\"jsonrpc\":\"2.0\",\"method\":\"$method\",\"params\":$params,\"id\":1}" and
the similar second call) to include connection and overall timeouts (for example
--connect-timeout 5 --max-time 10) so a stalled node/socket won’t hang CI; keep
the existing headers and piping to python3 unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 442c5b5a-2b3c-4deb-af81-3a72dbdffa67

📥 Commits

Reviewing files that changed from the base of the PR and between 2a96f46 and 7e19222.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • contracts/foundry.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • .github/workflows/ev_deployer.yml
  • Cargo.toml
  • bin/ev-deployer/Cargo.toml
  • bin/ev-deployer/README.md
  • bin/ev-deployer/examples/devnet.toml
  • bin/ev-deployer/src/config.rs
  • bin/ev-deployer/src/contracts/admin_proxy.rs
  • bin/ev-deployer/src/contracts/fee_vault.rs
  • bin/ev-deployer/src/contracts/mod.rs
  • bin/ev-deployer/src/genesis.rs
  • bin/ev-deployer/src/main.rs
  • bin/ev-deployer/src/output.rs
  • bin/ev-deployer/tests/e2e_genesis.sh
  • contracts/foundry.toml
  • justfile

Comment on lines +171 to +176
let forge_hex = String::from_utf8(output.stdout)
.unwrap()
.trim()
.strip_prefix("0x")
.unwrap()
.to_lowercase();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use non-panicking forge hex normalization in test.

Line 174/175 can panic if forge output unexpectedly omits 0x. Prefer tolerant normalization.

Suggested fix
-        let forge_hex = String::from_utf8(output.stdout)
-            .unwrap()
-            .trim()
-            .strip_prefix("0x")
-            .unwrap()
-            .to_lowercase();
+        let forge_hex = String::from_utf8(output.stdout)
+            .unwrap()
+            .trim()
+            .trim_start_matches("0x")
+            .to_lowercase();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/ev-deployer/src/contracts/fee_vault.rs` around lines 171 - 176, The
current normalization of forge output into forge_hex uses multiple unwraps and
can panic if the output is not valid UTF-8 or if the "0x" prefix is missing;
change it to a tolerant normalization that avoids unwraps by using
String::from_utf8_lossy on output.stdout and trim_start_matches("0x") instead of
strip_prefix/unwrap, e.g. build forge_hex from
String::from_utf8_lossy(&output.stdout).trim().trim_start_matches("0x").to_lowercase()
so it safely handles missing "0x" and invalid UTF-8.

Comment on lines +71 to +75
let result = if let Some(ref genesis_path) = merge_into {
genesis::merge_into(&cfg, genesis_path, force)?
} else {
genesis::build_alloc(&cfg)
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

--merge-into without --output drops merged result to stdout only.

When users pass --merge-into alone, the merged genesis is not written back to the source file. That makes merge behavior easy to misuse and lose.

Suggested fix (persist merge target by default)
-            if let Some(ref out_path) = output {
-                std::fs::write(out_path, &json)?;
-                eprintln!("Wrote alloc to {}", out_path.display());
-            } else {
-                println!("{json}");
-            }
+            if let Some(target_path) = output.as_ref().or(merge_into.as_ref()) {
+                std::fs::write(target_path, &json)?;
+                eprintln!("Wrote alloc to {}", target_path.display());
+            } else {
+                println!("{json}");
+            }

Also applies to: 79-84

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/ev-deployer/src/main.rs` around lines 71 - 75, When --merge-into is
provided but no explicit --output is given, the merged genesis currently only
goes to stdout; change the control flow so that when merge_into is
Some(genesis_path) and output is None you persist the merged result back to
genesis_path. Concretely, after calling genesis::merge_into(&cfg, genesis_path,
force) (or using the merged value from genesis::build_alloc when merging), write
the resulting genesis bytes/string to the same genesis_path (or call an existing
genesis write helper) instead of only printing to stdout; update the branch that
handles merge_into (and the similar branch around lines 79–84) to perform that
write when output is unspecified.

- Expand CI workflow path triggers to include Cargo.toml, Cargo.lock,
  and the workflow file itself
- Fix README merge behavior description (not in-place)
- Validate contract addresses are unique in config
- Use trim_start_matches("0x") instead of strip_prefix().unwrap() in
  bytecode verification tests
- Add curl timeouts to e2e test RPC calls to prevent CI hangs
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
bin/ev-deployer/src/contracts/fee_vault.rs (1)

171-175: ⚠️ Potential issue | 🟡 Minor

Avoid panic in forge output decoding path.

Line 171 still uses String::from_utf8(output.stdout).unwrap(), which can panic on unexpected bytes. Use lossy decoding to keep this parity test tolerant.

Proposed fix
-        let forge_hex = String::from_utf8(output.stdout)
-            .unwrap()
+        let forge_hex = String::from_utf8_lossy(&output.stdout)
             .trim()
             .trim_start_matches("0x")
             .to_lowercase();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/ev-deployer/src/contracts/fee_vault.rs` around lines 171 - 175, The
current forge_hex construction uses String::from_utf8(output.stdout).unwrap()
which can panic on invalid UTF-8; change the decoding to a lossy form (e.g. use
String::from_utf8_lossy on output.stdout) before
trim/trim_start_matches/to_lowercase so the parity test tolerates unexpected
bytes and avoids panics when building forge_hex.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@bin/ev-deployer/src/contracts/fee_vault.rs`:
- Around line 171-175: The current forge_hex construction uses
String::from_utf8(output.stdout).unwrap() which can panic on invalid UTF-8;
change the decoding to a lossy form (e.g. use String::from_utf8_lossy on
output.stdout) before trim/trim_start_matches/to_lowercase so the parity test
tolerates unexpected bytes and avoids panics when building forge_hex.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c7550381-d587-49ad-b622-1fca28fe6555

📥 Commits

Reviewing files that changed from the base of the PR and between 7e19222 and aeffc0d.

📒 Files selected for processing (6)
  • .github/workflows/ev_deployer.yml
  • bin/ev-deployer/README.md
  • bin/ev-deployer/src/config.rs
  • bin/ev-deployer/src/contracts/admin_proxy.rs
  • bin/ev-deployer/src/contracts/fee_vault.rs
  • bin/ev-deployer/tests/e2e_genesis.sh
✅ Files skipped from review due to trivial changes (2)
  • .github/workflows/ev_deployer.yml
  • bin/ev-deployer/README.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • bin/ev-deployer/src/config.rs
  • bin/ev-deployer/src/contracts/admin_proxy.rs
  • bin/ev-deployer/tests/e2e_genesis.sh

ev-deployer compute-address --config deploy.toml --contract admin_proxy
```

## Contracts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these optional to deploy?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I am gonna move them into ev-deployer directly.

Copy link
Contributor

@tac0turtle tac0turtle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, left one comment on optionality but otherwise super nice job

FeeVault will be added in a separate PR to keep this one focused on
AdminProxy only.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
bin/ev-deployer/tests/e2e_genesis.sh (2)

79-83: Use structured JSON validation for alloc presence instead of substring grep.

grep can false-positive on incidental matches and does not prove the address exists as an alloc key.

Suggested refactor
-# Quick sanity: address should be in the alloc
-grep -q "000000000000000000000000000000000000Ad00" "$GENESIS" \
-    || fail "AdminProxy address not found in genesis"
+python3 - "$GENESIS" <<'PY' || fail "AdminProxy address not found in genesis alloc"
+import json, sys
+genesis_path = sys.argv[1]
+with open(genesis_path, "r", encoding="utf-8") as f:
+    data = json.load(f)
+alloc = data.get("alloc", {})
+target = "000000000000000000000000000000000000ad00"
+keys = {k.lower()[2:] if k.lower().startswith("0x") else k.lower() for k in alloc.keys()}
+if target not in keys:
+    raise SystemExit(1)
+PY
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/ev-deployer/tests/e2e_genesis.sh` around lines 79 - 83, Replace the
fragile substring grep check that looks for
"000000000000000000000000000000000000Ad00" in "$GENESIS" with a structured JSON
key existence check using a JSON parser (e.g., jq) to assert the address is
present under the "alloc" object; update the test to call jq on "$GENESIS" to
test .alloc["0x000000000000000000000000000000000000Ad00"] (or the canonical
address form used elsewhere) and call fail() if jq indicates the key is missing,
otherwise call pass() — locate this logic around the existing GENESIS variable
reference and the fail/pass calls in the e2e_genesis.sh test.

109-125: Derive expected AdminProxy values from test input instead of hardcoding literals.

Duplicating ADMIN_PROXY/owner as constants makes this flow less sensitive to regressions in config ingestion. Prefer sourcing expected values from the same deploy input (or generated addresses manifest) before asserting RPC state.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/ev-deployer/tests/e2e_genesis.sh` around lines 109 - 125, The test
currently hardcodes expected AdminProxy values; change it to derive expectations
from the test inputs by using the existing ADMIN_OWNER (and ADMIN_PROXY)
variables rather than literal addresses: build expected_owner_slot by taking
ADMIN_OWNER, stripping the 0x, lowercasing it and left-padding with zeros to 64
hex chars and prefixing 0x, then compare that to admin_slot0 (normalized to
lowercase) produced by rpc_call; keep using ADMIN_PROXY when fetching admin_code
and use fail/pass as before. Ensure you reference the symbols ADMIN_OWNER,
ADMIN_PROXY, admin_code, admin_slot0, expected_owner_slot, rpc_call and fail so
the logic remains robust to changes in deploy inputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@bin/ev-deployer/tests/e2e_genesis.sh`:
- Around line 79-83: Replace the fragile substring grep check that looks for
"000000000000000000000000000000000000Ad00" in "$GENESIS" with a structured JSON
key existence check using a JSON parser (e.g., jq) to assert the address is
present under the "alloc" object; update the test to call jq on "$GENESIS" to
test .alloc["0x000000000000000000000000000000000000Ad00"] (or the canonical
address form used elsewhere) and call fail() if jq indicates the key is missing,
otherwise call pass() — locate this logic around the existing GENESIS variable
reference and the fail/pass calls in the e2e_genesis.sh test.
- Around line 109-125: The test currently hardcodes expected AdminProxy values;
change it to derive expectations from the test inputs by using the existing
ADMIN_OWNER (and ADMIN_PROXY) variables rather than literal addresses: build
expected_owner_slot by taking ADMIN_OWNER, stripping the 0x, lowercasing it and
left-padding with zeros to 64 hex chars and prefixing 0x, then compare that to
admin_slot0 (normalized to lowercase) produced by rpc_call; keep using
ADMIN_PROXY when fetching admin_code and use fail/pass as before. Ensure you
reference the symbols ADMIN_OWNER, ADMIN_PROXY, admin_code, admin_slot0,
expected_owner_slot, rpc_call and fail so the logic remains robust to changes in
deploy inputs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 16ba6325-c7f2-4619-9c3a-119a04863a7f

📥 Commits

Reviewing files that changed from the base of the PR and between aeffc0d and e8a39f8.

📒 Files selected for processing (8)
  • bin/ev-deployer/README.md
  • bin/ev-deployer/examples/devnet.toml
  • bin/ev-deployer/src/config.rs
  • bin/ev-deployer/src/contracts/mod.rs
  • bin/ev-deployer/src/genesis.rs
  • bin/ev-deployer/src/main.rs
  • bin/ev-deployer/src/output.rs
  • bin/ev-deployer/tests/e2e_genesis.sh
✅ Files skipped from review due to trivial changes (2)
  • bin/ev-deployer/src/contracts/mod.rs
  • bin/ev-deployer/README.md
🚧 Files skipped from review as they are similar to previous changes (5)
  • bin/ev-deployer/src/output.rs
  • bin/ev-deployer/examples/devnet.toml
  • bin/ev-deployer/src/main.rs
  • bin/ev-deployer/src/config.rs
  • bin/ev-deployer/src/genesis.rs

Keep only the CLI framework (config, genesis merge, manifest output)
without any contract implementations. Contracts will be added in
subsequent PRs.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
bin/ev-deployer/src/genesis.rs (1)

109-118: Cover the collision paths in tests.

This test only proves that an existing alloc entry survives when build_alloc() returns {}. It does not exercise the address collision error or the force overwrite branch, which are the core behaviors of this module.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/ev-deployer/src/genesis.rs` around lines 109 - 118, Add tests that
exercise the address-collision and force-overwrite branches of merge_into:
create a temp genesis file containing an alloc entry for a specific address,
then call merge_into(&test_config(), tmp.path(), false) with build_alloc()
returning a colliding address and assert it returns an error describing the
collision; then call merge_into(&test_config(), tmp.path(), true) and assert the
alloc entry is replaced/updated (e.g., the value written reflects the new
build_alloc result). Reference the existing test merge_into_existing_genesis and
the merge_into function (and the code path that checks/overwrites alloc entries)
to add two new tests — one expecting a collision error and one verifying
force=true overwrites the existing alloc entry.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/ev-deployer/src/genesis.rs`:
- Around line 31-35: Normalize alloc keys before checking collisions and
inserting: convert both the incoming key (addr from new_alloc) and existing keys
in genesis_alloc to a canonical address form (e.g., lowercase hex without 0x or
a checksum-normalized form) before calling genesis_alloc.contains_key(addr) and
before genesis_alloc.insert(...). In practice, compute a canonical_addr for each
addr (and ensure genesis_alloc is keyed by canonical forms or compare against
canonicalized existing keys) inside the loop that iterates new_alloc (the block
using variables addr and entry) so collision detection and insertion use the
same normalized representation.

In `@bin/ev-deployer/src/main.rs`:
- Around line 93-98: The ComputeAddress subcommand currently ignores the
provided config and always bails with "unknown contract"; update the
Command::ComputeAddress handling to first load and validate the config (use the
passed-in config path instead of _config_path so errors are surfaced) and
propagate any config file errors, then match on the contract name and return a
clear "not implemented yet" error for unsupported contracts (or remove/gate the
subcommand for part 1 if you prefer). Specifically, replace the unconditional
eyre::bail! in the Command::ComputeAddress arm with code that attempts to
read/parse the config, reports config load failures, and only then returns an
explicit not-implemented error for the contract branch of compute-address.

---

Nitpick comments:
In `@bin/ev-deployer/src/genesis.rs`:
- Around line 109-118: Add tests that exercise the address-collision and
force-overwrite branches of merge_into: create a temp genesis file containing an
alloc entry for a specific address, then call merge_into(&test_config(),
tmp.path(), false) with build_alloc() returning a colliding address and assert
it returns an error describing the collision; then call
merge_into(&test_config(), tmp.path(), true) and assert the alloc entry is
replaced/updated (e.g., the value written reflects the new build_alloc result).
Reference the existing test merge_into_existing_genesis and the merge_into
function (and the code path that checks/overwrites alloc entries) to add two new
tests — one expecting a collision error and one verifying force=true overwrites
the existing alloc entry.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7c54e065-9fde-42e2-8e3e-9a85c37a9ff9

📥 Commits

Reviewing files that changed from the base of the PR and between e8a39f8 and 089ef22.

📒 Files selected for processing (8)
  • bin/ev-deployer/README.md
  • bin/ev-deployer/examples/devnet.toml
  • bin/ev-deployer/src/config.rs
  • bin/ev-deployer/src/contracts/mod.rs
  • bin/ev-deployer/src/genesis.rs
  • bin/ev-deployer/src/main.rs
  • bin/ev-deployer/src/output.rs
  • bin/ev-deployer/tests/e2e_genesis.sh
✅ Files skipped from review due to trivial changes (3)
  • bin/ev-deployer/examples/devnet.toml
  • bin/ev-deployer/README.md
  • bin/ev-deployer/src/config.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • bin/ev-deployer/src/contracts/mod.rs
  • bin/ev-deployer/tests/e2e_genesis.sh
  • bin/ev-deployer/src/output.rs

Default to an empty ContractsConfig when the section is omitted,
so a minimal config only needs [chain].
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
bin/ev-deployer/src/config.rs (1)

50-60: Consider validating that admin_proxy.address is non-zero.

The validation ensures owner is not the zero address, but address (the deployment target) is not checked. A zero address would place the contract at 0x0, which is almost certainly unintended.

Suggested fix
     fn validate(&self) -> eyre::Result<()> {
         if let Some(ref ap) = self.contracts.admin_proxy {
+            eyre::ensure!(
+                !ap.address.is_zero(),
+                "admin_proxy.address must not be the zero address"
+            );
             eyre::ensure!(
                 !ap.owner.is_zero(),
                 "admin_proxy.owner must not be the zero address"
             );
         }

         Ok(())
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/ev-deployer/src/config.rs` around lines 50 - 60, The validate() method
currently checks admin_proxy.owner but not admin_proxy.address; update validate
(the fn validate(&self) -> eyre::Result<()>) to also ensure the
admin_proxy.address is not the zero address by adding an
eyre::ensure!(!ap.address.is_zero(), "admin_proxy.address must not be the zero
address") alongside the existing owner check so both ap.owner and ap.address are
validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/ev-deployer/src/main.rs`:
- Around line 52-53: The help text for the --contract arg mentions "fee_vault"
but only "admin_proxy" is handled, so either remove "fee_vault" from the
docstring or implement support for it in the command handling; to fix, either
update the doc comment above the #[arg(long)] so it lists only "admin_proxy", or
add a matching branch in the ComputeAddress logic (e.g., the match handling the
contract name in ComputeAddress) that recognizes "fee_vault" and
computes/returns the correct address/behavior for it; ensure the symbol
ComputeAddress (and whatever enum/handler that matches contract names) is
updated accordingly so help text and runtime behavior remain consistent.

---

Nitpick comments:
In `@bin/ev-deployer/src/config.rs`:
- Around line 50-60: The validate() method currently checks admin_proxy.owner
but not admin_proxy.address; update validate (the fn validate(&self) ->
eyre::Result<()>) to also ensure the admin_proxy.address is not the zero address
by adding an eyre::ensure!(!ap.address.is_zero(), "admin_proxy.address must not
be the zero address") alongside the existing owner check so both ap.owner and
ap.address are validated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3f93c772-ab31-42a1-b97a-0d88098125c9

📥 Commits

Reviewing files that changed from the base of the PR and between 089ef22 and 6b85563.

📒 Files selected for processing (9)
  • bin/ev-deployer/README.md
  • bin/ev-deployer/examples/devnet.toml
  • bin/ev-deployer/src/config.rs
  • bin/ev-deployer/src/contracts/admin_proxy.rs
  • bin/ev-deployer/src/contracts/mod.rs
  • bin/ev-deployer/src/genesis.rs
  • bin/ev-deployer/src/main.rs
  • bin/ev-deployer/src/output.rs
  • bin/ev-deployer/tests/e2e_genesis.sh
✅ Files skipped from review due to trivial changes (3)
  • bin/ev-deployer/examples/devnet.toml
  • bin/ev-deployer/src/contracts/mod.rs
  • bin/ev-deployer/README.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • bin/ev-deployer/src/output.rs
  • bin/ev-deployer/tests/e2e_genesis.sh
  • bin/ev-deployer/src/genesis.rs

Generates a TOML config template with all supported contracts
commented out and documented.
…ence

Move Init subcommand first in help output and remove leftover
fee_vault mention from --contract flag doc.
Canonicalize address keys (lowercase, strip 0x) before comparing
during merge, so collisions are detected regardless of case or prefix
in the existing genesis file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants