Skip to content

feat: add cli methods for ciphernode registration [skip-line-limit]#1089

Merged
hmzakhalid merged 6 commits into
mainfrom
feat/cli-commands
Dec 8, 2025
Merged

feat: add cli methods for ciphernode registration [skip-line-limit]#1089
hmzakhalid merged 6 commits into
mainfrom
feat/cli-commands

Conversation

@hmzakhalid

@hmzakhalid hmzakhalid commented Dec 8, 2025

Copy link
Copy Markdown
Collaborator
Command Purpose
enclave ciphernode status [--chain <name>] Summarize registration state, balances, and requirements
enclave ciphernode license bond --amount <ENCL> Stake ENCL into the registry
enclave ciphernode license unbond --amount <ENCL> Start the exit timer for staked ENCL
enclave ciphernode license claim [--max-ticket <amount>] [--max-license <amount>] Withdraw unlocked exits
enclave ciphernode tickets buy --amount <stablecoin> Deposit stablecoins to mint tickets
enclave ciphernode tickets burn --amount <tickets> Withdraw tickets back to the underlying token
enclave ciphernode register Register the operator once minimum collateral is met
enclave ciphernode activate Force activation checks after bonding/ticket updates
enclave ciphernode deactivate [--tickets <amount>] [--license <amount>] Voluntarily exit collateral to go inactive
enclave ciphernode deregister --proof <node1,node2,...> Submit an IMT proof to leave the registry entirely

Amounts accept decimals (123.45) or visual separators (1_000). The CLI automatically fetches
token decimals, normalizes the number, and sets ERC-20 allowances as needed before calling the
contracts.

Summary by CodeRabbit

  • New Features
    • Added a Ciphernode CLI subsystem for operator management (license bonding/unbonding/claiming), ticket operations (buy/burn), and lifecycle commands (register, deregister, activate, deactivate, status).
    • Registry now exposes getters to query license and ticket token addresses on-chain.
    • Token artifact for EnclaveTicketToken is now tracked, enabling token contract visibility and use.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel

vercel Bot commented Dec 8, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
crisp Ready Ready Preview Comment Dec 8, 2025 8:50pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
enclave-docs Skipped Skipped Dec 8, 2025 8:50pm

@coderabbitai

coderabbitai Bot commented Dec 8, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a new Ciphernode CLI subsystem: a ChainContext for chain-aware provider/signer setup, license and ticket command handlers, lifecycle operations, ERC20 helpers, contract bindings and artifacts for EnclaveTicketToken, and two workspace dependencies (alloy, e3-evm) wired into the CLI crate.

Changes

Cohort / File(s) Summary
Dependency additions
crates/cli/Cargo.toml
Adds workspace dependencies alloy and e3-evm under [dependencies].
CLI integration
crates/cli/src/main.rs, crates/cli/src/cli.rs
Adds mod ciphernode; and a new Commands::Ciphernode { command: CiphernodeCommands } variant; routes Ciphernode subcommands into the CLI dispatch.
Ciphernode CLI surface
crates/cli/src/ciphernode/mod.rs
New CLI types/flags: ChainArgs, CiphernodeCommands, LicenseCommands, TicketCommands; top-level execute dispatch that builds ChainContext and delegates to submodules.
Chain context & bindings
crates/cli/src/ciphernode/context.rs
New ChainContext that selects a chain, initializes provider + signer, stores operator and bonding registry, and exposes contract bindings (BondingRegistry, EnclaveToken, EnclaveTicketToken, IERC20Metadata) and helpers to resolve token/underlying addresses.
License flows
crates/cli/src/ciphernode/license.rs
New handlers for Bond, Unbond, Claim flows; includes execute and bond_license with allowance checks, bonding/unbonding, claimExits calls, and tx receipt printing.
Ticket flows
crates/cli/src/ciphernode/tickets.rs
New execute supporting Buy and Burn: decimals resolution, amount parsing, ensure allowance, bonding add/remove ticket balance, and receipt output.
Lifecycle commands
crates/cli/src/ciphernode/lifecycle.rs
New functions: register, deregister, activate, deactivate, status — perform on-chain transactions/queries via ChainContext and print statuses/tx info.
Helpers / utilities
crates/cli/src/ciphernode/utils.rs
Adds format_amount, parse_amount, parse_u256_list, and async ensure_allowance for ERC20 parsing/formatting and approval flows.
Contract artifacts / interfaces
packages/enclave-contracts/contracts/interfaces/IBondingRegistry.sol, packages/enclave-contracts/contracts/registry/BondingRegistry.sol, packages/enclave-contracts/artifacts/.../IBondingRegistry.json, packages/enclave-contracts/artifacts/.../EnclaveTicketToken.json, packages/enclave-contracts/contracts/token/EnclaveTicketToken.sol
Adds getLicenseToken() and getTicketToken() to IBondingRegistry interface and BondingRegistry implementation; adds EnclaveTicketToken artifact and associated build metadata updates; updates artifact buildInfoId fields.
.gitignore adjustments
packages/enclave-contracts/.gitignore
Unignores token artifact files for EnclaveTicketToken so they are tracked in VCS.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant ChainContext
    participant Provider
    participant ERC20
    participant BondingRegistry

    User->>CLI: ciphernode tickets buy <amount> --chain <x>
    CLI->>ChainContext: ChainContext::new(config, selection)
    ChainContext->>Provider: init RPC + signer
    Provider-->>ChainContext: provider ready
    ChainContext-->>CLI: context

    CLI->>ChainContext: ticket_token_address()
    ChainContext->>BondingRegistry: bonding.ticketToken()
    BondingRegistry-->>ChainContext: ticket_token_addr
    ChainContext-->>CLI: ticket_token_addr

    CLI->>ChainContext: erc20(ticket_token_addr)
    ChainContext-->>CLI: ERC20 instance
    CLI->>ERC20: decimals()
    ERC20-->>CLI: decimals
    CLI->>CLI: parse_amount(input, decimals)
    CLI->>ChainContext: ensure_allowance(token, bonding_addr, amount)
    ChainContext->>ERC20: allowance(operator, bonding_addr)
    ERC20-->>ChainContext: current_allowance
    alt allowance < amount
        ChainContext->>ERC20: approve(bonding_addr, amount)
        ERC20-->>Provider: tx
        Provider-->>ChainContext: receipt
    end
    ChainContext-->>CLI: allowance ensured

    CLI->>ChainContext: bonding()
    ChainContext-->>CLI: BondingRegistry instance
    CLI->>BondingRegistry: addTicketBalance(amount)
    BondingRegistry-->>Provider: tx
    Provider-->>CLI: tx_receipt
    CLI->>User: print tx hash / confirmation
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay special attention to:
    • crates/cli/src/ciphernode/context.rs — chain selection, provider/signer initialization, address parsing, and generated contract bindings.
    • Async transaction flows and proper awaiting/receipt handling in license.rs, tickets.rs, and lifecycle.rs.
    • utils.rs parsing precision and potential edge cases around decimals and large U256 values.
    • ABI/artifact consistency: IBondingRegistry additions and EnclaveTicketToken artifact metadata.

Possibly related PRs

Suggested labels

crisp

Suggested reviewers

  • ryardley
  • ctrlc03

Poem

🐰 Hopping through bytes, I bind and send,

Chains and tokens — to each my friend.
I fetch decimals, parse with care,
Approve and bond — receipts to share.
A tiny hop — the CLI is fair! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.57% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding CLI methods for ciphernode registration, which is the primary focus of this PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/cli-commands

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.

@hmzakhalid hmzakhalid changed the title feat: add cli methods for ciphernode registration feat: add cli methods for ciphernode registration Dec 8, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
crates/cli/src/ciphernode/tickets.rs (1)

34-37: Unused variable ticket_contract.

The ticket_contract variable is fetched on line 35 but never used. The decimals are fetched directly on line 36 using ctx.ticket_token_address().await? again, making line 35 redundant. Consider removing it or using the variable consistently.

         TicketCommands::Burn { amount } => {
-            let ticket_contract = ctx.ticket_token_address().await?;
-            let decimals = ctx.erc20(ticket_contract).decimals().call().await?;
+            let ticket_token = ctx.ticket_token_address().await?;
+            let decimals = ctx.erc20(ticket_token).decimals().call().await?;
             let parsed = parse_amount(&amount, decimals)?;
crates/cli/src/ciphernode/utils.rs (1)

91-109: Consider informing users about approval transactions.

The ensure_allowance function silently approves tokens when needed. For CLI transparency, consider printing a message when an approval transaction is sent, so users are aware of the additional transaction.

+    if current < amount {
+        println!("Approving {} to spend tokens...", spender);
+    }
+
     erc20
         .approve(spender, amount)
         .send()
         .await?
         .get_receipt()
         .await?;
crates/cli/src/ciphernode/lifecycle.rs (1)

45-47: Clarify the relationship between activate and register.

The activate function simply delegates to register. While this may be intentionally aliased (the smart contract's registerOperator might handle both initial registration and reactivation), the current implementation could confuse users who expect different behavior. Consider adding a comment explaining this design decision.

+/// Activate the operator. This is functionally equivalent to calling register,
+/// as the contract's registerOperator handles both initial registration and
+/// reactivation after meeting collateral requirements.
 pub(crate) async fn activate(ctx: &ChainContext) -> Result<()> {
     register(ctx).await
 }
crates/cli/src/ciphernode/context.rs (1)

123-139: Consider caching token addresses if called multiple times.

The async methods license_token_address(), ticket_token_address(), and ticket_underlying_address() make RPC calls on each invocation. For CLI commands that only call these once, this is fine. If any command path calls these multiple times, caching the results would reduce RPC overhead.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8aff7c and feff81b.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • crates/cli/Cargo.toml (2 hunks)
  • crates/cli/src/ciphernode/context.rs (1 hunks)
  • crates/cli/src/ciphernode/license.rs (1 hunks)
  • crates/cli/src/ciphernode/lifecycle.rs (1 hunks)
  • crates/cli/src/ciphernode/mod.rs (1 hunks)
  • crates/cli/src/ciphernode/tickets.rs (1 hunks)
  • crates/cli/src/ciphernode/utils.rs (1 hunks)
  • crates/cli/src/cli.rs (3 hunks)
  • crates/cli/src/main.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-09-26T03:11:29.311Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/enclave/src/commands/wallet/set.rs:17-23
Timestamp: 2024-10-28T12:00:09.010Z
Learning: In the `enclave` package of the `ciphernode` project, prefer using `println!` over logging macros like `error!` from the `tracing` crate for error output in CLI commands.
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/keyshare/src/encryption.rs:45-45
Timestamp: 2024-10-23T02:03:02.008Z
Learning: In the `packages/ciphernode/keyshare/src/encryption.rs` file, the environment variable `CIPHERNODE_SECRET` is used for the encryption password. A secure secret management solution is not currently available, but may be considered in future iterations.
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/config/src/app_config.rs:13-21
Timestamp: 2024-11-05T06:48:58.177Z
Learning: In the `packages/ciphernode/config/src/app_config.rs` file, for the `Contract` enum, the team prefers to use `String` type for `address` fields, relying on parsing to handle validation, instead of using the `Address` type.
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.

Applied to files:

  • crates/cli/src/cli.rs
  • crates/cli/src/main.rs
  • crates/cli/src/ciphernode/utils.rs
  • crates/cli/src/ciphernode/lifecycle.rs
  • crates/cli/src/ciphernode/license.rs
  • crates/cli/src/ciphernode/context.rs
  • crates/cli/Cargo.toml
  • crates/cli/src/ciphernode/mod.rs
📚 Learning: 2024-10-28T12:00:09.010Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/enclave/src/commands/wallet/set.rs:17-23
Timestamp: 2024-10-28T12:00:09.010Z
Learning: In the `enclave` package of the `ciphernode` project, prefer using `println!` over logging macros like `error!` from the `tracing` crate for error output in CLI commands.

Applied to files:

  • crates/cli/src/cli.rs
  • crates/cli/src/main.rs
  • crates/cli/src/ciphernode/license.rs
  • crates/cli/src/ciphernode/mod.rs
📚 Learning: 2024-10-23T02:03:02.008Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/keyshare/src/encryption.rs:45-45
Timestamp: 2024-10-23T02:03:02.008Z
Learning: In the `packages/ciphernode/keyshare/src/encryption.rs` file, the environment variable `CIPHERNODE_SECRET` is used for the encryption password. A secure secret management solution is not currently available, but may be considered in future iterations.

Applied to files:

  • crates/cli/src/cli.rs
  • crates/cli/src/main.rs
📚 Learning: 2024-10-28T12:04:26.578Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/enclave_node/src/ciphernode.rs:26-28
Timestamp: 2024-10-28T12:04:26.578Z
Learning: In the `setup_ciphernode` function in `packages/ciphernode/enclave_node/src/ciphernode.rs`, panicking on errors during setup is acceptable.

Applied to files:

  • crates/cli/src/cli.rs
  • crates/cli/src/main.rs
  • crates/cli/src/ciphernode/mod.rs
📚 Learning: 2024-10-28T10:59:42.202Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/config/src/app_config.rs:146-175
Timestamp: 2024-10-28T10:59:42.202Z
Learning: In `packages/ciphernode/config/src/app_config.rs`, the `normalize_path` function uses custom path normalization instead of `std::fs::canonicalize` because using `canonicalize` requires actual files to exist, making testing more difficult.

Applied to files:

  • crates/cli/src/cli.rs
📚 Learning: 2024-10-23T01:59:42.967Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:274-274
Timestamp: 2024-10-23T01:59:42.967Z
Learning: In the `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs` file and other test files within this project, hardcoding `CIPHERNODE_SECRET` is acceptable for testing purposes.

Applied to files:

  • crates/cli/src/cli.rs
  • crates/cli/src/main.rs
📚 Learning: 2024-11-05T06:48:58.177Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/config/src/app_config.rs:13-21
Timestamp: 2024-11-05T06:48:58.177Z
Learning: In the `packages/ciphernode/config/src/app_config.rs` file, for the `Contract` enum, the team prefers to use `String` type for `address` fields, relying on parsing to handle validation, instead of using the `Address` type.

Applied to files:

  • crates/cli/src/cli.rs
  • crates/cli/src/ciphernode/context.rs
📚 Learning: 2024-10-29T01:03:50.414Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/config/src/app_config.rs:21-26
Timestamp: 2024-10-29T01:03:50.414Z
Learning: In `packages/ciphernode/config/src/app_config.rs`, the `rpc_url` field in the `ChainConfig` struct is not considered sensitive and does not need to be encrypted.

Applied to files:

  • crates/cli/src/cli.rs
📚 Learning: 2024-11-05T06:49:46.285Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/enclave_node/src/datastore.rs:14-16
Timestamp: 2024-11-05T06:49:46.285Z
Learning: In `packages/ciphernode/enclave_node/src/datastore.rs`, for internal functions like `get_in_mem_store`, adding extensive documentation and error handling may not be necessary if they are not client-facing.

Applied to files:

  • crates/cli/src/ciphernode/utils.rs
📚 Learning: 2024-10-12T10:24:07.572Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.

Applied to files:

  • crates/cli/src/ciphernode/context.rs
📚 Learning: 2025-08-25T10:28:56.174Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 657
File: Cargo.toml:32-34
Timestamp: 2025-08-25T10:28:56.174Z
Learning: The examples/CRISP directory has its own Cargo.toml workspace configuration with members like "server", "wasm-crypto", "program/core", "program/client", etc. The root workspace intentionally excludes "examples/CRISP/server", "examples/CRISP/program", and "examples/CRISP/wasm-crypto" to prevent double workspace membership, which is the correct approach for self-contained example workspaces.

Applied to files:

  • crates/cli/Cargo.toml
📚 Learning: 2024-10-22T02:36:01.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/Cargo.toml:0-0
Timestamp: 2024-10-22T02:36:01.448Z
Learning: In `packages/ciphernode/data/Cargo.toml`, `actix-rt` is only used in tests and should remain in `[dev-dependencies]`.

Applied to files:

  • crates/cli/Cargo.toml
🧬 Code graph analysis (6)
crates/cli/src/cli.rs (1)
crates/cli/src/ciphernode/mod.rs (1)
  • execute (123-163)
crates/cli/src/ciphernode/tickets.rs (1)
crates/cli/src/ciphernode/utils.rs (2)
  • ensure_allowance (91-110)
  • parse_amount (33-69)
crates/cli/src/ciphernode/utils.rs (1)
crates/cli/src/ciphernode/context.rs (1)
  • erc20 (141-146)
crates/cli/src/ciphernode/lifecycle.rs (3)
crates/utils/src/actix.rs (1)
  • bail (12-14)
crates/cli/src/ciphernode/utils.rs (3)
  • format_amount (14-31)
  • parse_amount (33-69)
  • parse_u256_list (71-77)
crates/cli/src/ciphernode/context.rs (2)
  • chain_label (115-117)
  • operator (111-113)
crates/cli/src/ciphernode/license.rs (4)
crates/cli/src/ciphernode/utils.rs (2)
  • ensure_allowance (91-110)
  • parse_amount (33-69)
crates/cli/src/ciphernode/mod.rs (1)
  • execute (123-163)
crates/cli/src/ciphernode/tickets.rs (1)
  • execute (13-53)
crates/cli/src/ciphernode/context.rs (2)
  • chain_label (115-117)
  • erc20 (141-146)
crates/cli/src/ciphernode/mod.rs (5)
crates/cli/src/ciphernode/license.rs (1)
  • execute (14-90)
crates/cli/src/ciphernode/tickets.rs (1)
  • execute (13-53)
crates/cli/src/cli.rs (1)
  • execute (85-200)
crates/cli/src/ciphernode/context.rs (1)
  • new (78-99)
crates/cli/src/ciphernode/lifecycle.rs (5)
  • register (13-27)
  • deregister (29-43)
  • activate (45-47)
  • deactivate (49-96)
  • status (98-145)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: integration_prebuild
  • GitHub Check: build_enclave_cli
  • GitHub Check: test_net
  • GitHub Check: test_contracts
  • GitHub Check: build_ciphernode_image
  • GitHub Check: build_sdk
  • GitHub Check: crisp_unit
  • GitHub Check: rust_unit
  • GitHub Check: rust_integration
🔇 Additional comments (19)
crates/cli/src/main.rs (1)

11-11: LGTM!

The module declaration follows the existing pattern and correctly integrates the new ciphernode subsystem into the CLI crate.

crates/cli/Cargo.toml (1)

15-15: LGTM!

The new workspace dependencies (alloy and e3-evm) are correctly declared and align with the blockchain interaction requirements of the ciphernode subsystem.

Also applies to: 24-24

crates/cli/src/cli.rs (1)

9-9: LGTM!

The ciphernode command integration follows the established CLI patterns:

  • Import mirrors other command module imports
  • Dispatch follows the same pattern as existing subcommands (Password, Wallet, Net)
  • Enum variant is correctly structured with the flattened subcommand

Also applies to: 192-192, 293-297

crates/cli/src/ciphernode/tickets.rs (1)

13-53: LGTM!

The ticket operations are well-structured:

  • Buy correctly ensures allowance on the underlying token before depositing
  • Burn properly retrieves decimals for amount parsing
  • Both commands print transaction receipts per project conventions
crates/cli/src/ciphernode/license.rs (2)

14-90: LGTM!

The license command implementation is well-structured:

  • Acquire correctly handles dev/faucet minting with allocation metadata
  • Bond uses the helper function with proper allowance checking
  • Unbond queues exits appropriately
  • Claim uses U256::MAX as a sensible default to claim all available exits
  • Error handling and receipt printing are consistent throughout

92-110: LGTM on bond_license helper.

The helper correctly ensures ERC20 allowance is set before calling the bonding contract, following the same pattern used in tickets.

crates/cli/src/ciphernode/utils.rs (2)

14-31: LGTM!

The format_amount function correctly handles:

  • Zero fractional parts (returns integer only)
  • Trailing zero trimming in fractional parts
  • Proper padding for fractional parts shorter than decimals

33-69: LGTM!

The parse_amount function correctly:

  • Normalizes input by stripping underscores (visual separators)
  • Validates decimal precision against token decimals
  • Handles edge cases like empty fractional parts after decimal point
  • Preserves leading zeros in fractional parts (e.g., "1.01" → correct value)
crates/cli/src/ciphernode/lifecycle.rs (2)

98-144: LGTM on status output.

The status function provides comprehensive and well-formatted output covering:

  • Registration and activation state
  • Ticket and license balances with proper decimal formatting
  • Pending exits
  • System requirements

The sequential RPC calls are acceptable for a CLI status command.


13-27: LGTM on lifecycle operations.

The register, deregister, and deactivate functions are well-implemented:

  • Proper validation in deactivate ensuring at least one withdrawal type is specified
  • Correct use of parse_u256_list for IMT proof siblings
  • Consistent error handling and receipt printing

Also applies to: 29-43, 49-96

crates/cli/src/ciphernode/mod.rs (4)

19-30: LGTM!

The ChainArgs struct with the selection() helper provides clean chain selection that integrates well with clap's flatten pattern.


32-79: LGTM on command definitions.

The CiphernodeCommands enum is well-structured:

  • Clear help text for each command
  • Proper use of #[command(flatten)] for the shared ChainArgs
  • Deregister uses value_delimiter for comma-separated IMT proof nodes
  • Deactivate uses optional amounts allowing flexible withdrawal combinations

81-121: LGTM on subcommand definitions.

LicenseCommands and TicketCommands are properly structured with:

  • Clear help text describing each operation
  • String-based amounts to support decimal input with the parse_amount utility
  • Sensible default for allocation in Acquire

123-163: LGTM on the execute dispatcher.

The dispatcher correctly:

  • Creates a ChainContext for each command variant
  • Delegates to the appropriate module (license, tickets, lifecycle)
  • Follows the established pattern from other CLI modules
  • Properly propagates errors with ?
crates/cli/src/ciphernode/context.rs (5)

1-17: LGTM!

License header and imports are well-organized. The use of alloy::primitives::Address aligns with established patterns in the codebase.


19-68: Clean contract binding organization.

The sol! macro bindings are well-structured. The inline IERC20Metadata interface definition avoids external ABI dependencies while providing just the needed functions. The separate module pattern keeps generated code isolated.


70-75: LGTM!

The struct design cleanly encapsulates chain-specific state with appropriate visibility.


77-99: Well-structured async constructor.

The initialization flow is clear: chain selection → address parsing → cipher/signer loading → provider setup. Error propagation with ? ensures failures surface with context from the underlying calls.


156-172: LGTM!

Clear error messages guide users toward resolution. The select_chain function correctly returns a reference, and parse_address follows the team's pattern of using String in config with validation at parse time. Based on learnings, this aligns with the established approach in the codebase.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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)
crates/cli/src/ciphernode/context.rs (1)

138-154: Optional: enrich address parsing errors with chain/field context

parse_address currently wraps failures with a generic "Invalid address in configuration" message. If you ever find debugging misconfigured chains painful, consider threading through the chain name and field (e.g., "bonding_registry") so the error points directly at the offending entry. Not urgent, but it would improve operator UX when configs are wrong.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between feff81b and 1e5a174.

📒 Files selected for processing (3)
  • crates/cli/src/ciphernode/context.rs (1 hunks)
  • crates/cli/src/ciphernode/license.rs (1 hunks)
  • crates/cli/src/ciphernode/mod.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-09-26T03:11:29.311Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.

Applied to files:

  • crates/cli/src/ciphernode/mod.rs
  • crates/cli/src/ciphernode/context.rs
📚 Learning: 2024-10-12T10:24:07.572Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.

Applied to files:

  • crates/cli/src/ciphernode/mod.rs
  • crates/cli/src/ciphernode/context.rs
📚 Learning: 2024-10-28T12:00:09.010Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/enclave/src/commands/wallet/set.rs:17-23
Timestamp: 2024-10-28T12:00:09.010Z
Learning: In the `enclave` package of the `ciphernode` project, prefer using `println!` over logging macros like `error!` from the `tracing` crate for error output in CLI commands.

Applied to files:

  • crates/cli/src/ciphernode/mod.rs
📚 Learning: 2024-10-28T12:04:26.578Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/enclave_node/src/ciphernode.rs:26-28
Timestamp: 2024-10-28T12:04:26.578Z
Learning: In the `setup_ciphernode` function in `packages/ciphernode/enclave_node/src/ciphernode.rs`, panicking on errors during setup is acceptable.

Applied to files:

  • crates/cli/src/ciphernode/mod.rs
📚 Learning: 2024-11-05T06:48:58.177Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/config/src/app_config.rs:13-21
Timestamp: 2024-11-05T06:48:58.177Z
Learning: In the `packages/ciphernode/config/src/app_config.rs` file, for the `Contract` enum, the team prefers to use `String` type for `address` fields, relying on parsing to handle validation, instead of using the `Address` type.

Applied to files:

  • crates/cli/src/ciphernode/context.rs
🧬 Code graph analysis (1)
crates/cli/src/ciphernode/mod.rs (4)
crates/cli/src/ciphernode/license.rs (1)
  • execute (14-72)
crates/cli/src/ciphernode/tickets.rs (1)
  • execute (13-53)
crates/cli/src/ciphernode/context.rs (1)
  • new (67-88)
crates/cli/src/ciphernode/lifecycle.rs (5)
  • register (13-27)
  • deregister (29-43)
  • activate (45-47)
  • deactivate (49-96)
  • status (98-145)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: crisp_unit
  • GitHub Check: build_sdk
  • GitHub Check: rust_unit
  • GitHub Check: rust_integration
  • GitHub Check: integration_prebuild
  • GitHub Check: test_contracts
  • GitHub Check: build_enclave_cli
  • GitHub Check: test_net
  • GitHub Check: build_ciphernode_image
🔇 Additional comments (5)
crates/cli/src/ciphernode/license.rs (2)

14-69: License command dispatch looks consistent and correctly typed

The Bond/Unbond/Claim branches correctly resolve token addresses, fetch decimals, parse user amounts, and call the expected bonding methods, matching the patterns used in tickets.rs and lifecycle.rs. Error propagation is clean and the user-facing messages are clear.


74-92: Bond flow correctly handles decimals, allowance, and bonding

bond_license resolves the license token, uses on-chain decimals with parse_amount, ensures allowance to the bonding registry before calling bondLicense, and prints a concise receipt. This is a solid, reusable pattern for future token flows.

crates/cli/src/ciphernode/context.rs (1)

66-88: ChainContext::new is cohesive and keeps concerns well‑isolated

The constructor cleanly handles chain selection, address parsing, key/cipher loading, signer derivation, and provider setup, then stores only what the CLI needs (label, registry address, provider, signer address). This keeps on‑chain wiring out of the command modules and should be easy to extend if the chain config grows.

crates/cli/src/ciphernode/mod.rs (2)

19-79: CLI command shapes and clap wiring align with the described UX

The CiphernodeCommands, LicenseCommands, and TicketCommands enums map cleanly onto the intended CLI (license, tickets, register, deregister, activate, deactivate, status), and the clap attributes (flatten for ChainArgs, value_delimiter for --proof, explicit --amount flags) should give a predictable UX for operators.

If you haven’t already, a quick enclave ciphernode --help / enclave ciphernode license --help pass to visually confirm the generated help text matches the docs would be worthwhile.


116-156: Dispatcher cleanly constructs per‑command ChainContext instances

The top‑level execute function consistently builds a ChainContext from ChainArgs::selection() and delegates to the appropriate module (license, tickets, lifecycle), keeping each branch simple and side‑effect free beyond the intended on‑chain call. The small duplication around ChainContext::new is fine at this scale and keeps each arm easy to read.

Comment thread crates/cli/src/ciphernode/context.rs
@hmzakhalid hmzakhalid changed the title feat: add cli methods for ciphernode registration feat: add cli methods for ciphernode registration [skip-line-limit] Dec 8, 2025

@ctrlc03 ctrlc03 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

utACK - just one question

Comment thread crates/cli/src/ciphernode/context.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
crates/cli/src/ciphernode/context.rs (1)

67-80: Consider stricter validation and clearer errors for the bonding registry address

Right now bonding_registry is only parsed, and parse_address reports a generic "Invalid address in configuration" error. You might want to (a) treat the zero address as invalid and (b) add chain/field context to the error (bonding_registry for chain X) so misconfigurations are easier to diagnose from the CLI.

Also applies to: 138-154

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e5a174 and 2783a1d.

📒 Files selected for processing (7)
  • crates/cli/src/ciphernode/context.rs (1 hunks)
  • packages/enclave-contracts/.gitignore (1 hunks)
  • packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json (3 hunks)
  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json (1 hunks)
  • packages/enclave-contracts/artifacts/contracts/token/EnclaveTicketToken.sol/EnclaveTicketToken.json (1 hunks)
  • packages/enclave-contracts/contracts/interfaces/IBondingRegistry.sol (1 hunks)
  • packages/enclave-contracts/contracts/registry/BondingRegistry.sol (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/enclave/src/commands/wallet/set.rs:17-23
Timestamp: 2024-10-28T12:00:09.010Z
Learning: In the `enclave` package of the `ciphernode` project, prefer using `println!` over logging macros like `error!` from the `tracing` crate for error output in CLI commands.
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/keyshare/src/encryption.rs:45-45
Timestamp: 2024-10-23T02:03:02.008Z
Learning: In the `packages/ciphernode/keyshare/src/encryption.rs` file, the environment variable `CIPHERNODE_SECRET` is used for the encryption password. A secure secret management solution is not currently available, but may be considered in future iterations.
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-09-26T03:11:29.311Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.
📚 Learning: 2025-09-19T11:16:53.825Z
Learnt from: cedoor
Repo: gnosisguild/enclave PR: 752
File: packages/enclave-contracts/contracts/Enclave.sol:15-17
Timestamp: 2025-09-19T11:16:53.825Z
Learning: The Enclave contract in the gnosisguild/enclave repository has not been deployed yet as of September 2025, so storage layout considerations for upgradeable contracts don't apply to current changes.

Applied to files:

  • packages/enclave-contracts/artifacts/contracts/token/EnclaveTicketToken.sol/EnclaveTicketToken.json
📚 Learning: 2024-11-05T06:48:58.177Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/config/src/app_config.rs:13-21
Timestamp: 2024-11-05T06:48:58.177Z
Learning: In the `packages/ciphernode/config/src/app_config.rs` file, for the `Contract` enum, the team prefers to use `String` type for `address` fields, relying on parsing to handle validation, instead of using the `Address` type.

Applied to files:

  • crates/cli/src/ciphernode/context.rs
📚 Learning: 2024-10-12T10:24:07.572Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.

Applied to files:

  • crates/cli/src/ciphernode/context.rs
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.

Applied to files:

  • crates/cli/src/ciphernode/context.rs
📚 Learning: 2024-10-22T03:39:29.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/evm/src/enclave_sol_reader.rs:87-89
Timestamp: 2024-10-22T03:39:29.448Z
Learning: In the `ciphernode` project, specifically in `packages/ciphernode/evm/src/enclave_sol_reader.rs`, the method `EnclaveSolReader::attach` should be retained even if it directly calls `EvmEventReader::attach` without additional processing. Avoid suggesting its removal in future reviews.

Applied to files:

  • crates/cli/src/ciphernode/context.rs
🔇 Additional comments (6)
packages/enclave-contracts/.gitignore (1)

11-11: LGTM!

The unignore rules follow the established pattern for tracking generated contract artifacts. Lines 11, 15, and 19 correctly unignore the token directory, the EnclaveTicketToken.sol subdirectory, and the corresponding JSON artifact—mirroring the existing structure for interfaces and registry contracts.

Also applies to: 15-15, 19-19

packages/enclave-contracts/artifacts/contracts/token/EnclaveTicketToken.sol/EnclaveTicketToken.json (1)

1-1222: Artifact ABI and path look consistent with CLI usage

The EnclaveTicketToken artifact is well‑formed, exposes the expected methods (underlying, deposit/mint/burn/payout), and its path matches the sol! import in the CLI; no issues from a contracts/CLI integration perspective.

packages/enclave-contracts/contracts/interfaces/IBondingRegistry.sol (1)

116-127: New token address getters are consistent and non‑breaking

Adding getLicenseToken / getTicketToken as view functions returning address cleanly complements the existing setters and doesn’t affect storage or existing callers; interface shape looks good.

packages/enclave-contracts/contracts/registry/BondingRegistry.sol (1)

189-197: Getter implementations correctly expose token addresses without changing storage

getLicenseToken / getTicketToken reuse existing public fields and only cast to address, so they’re upgrade‑safe and align with the IBondingRegistry interface and CLI needs.

packages/enclave-contracts/artifacts/contracts/interfaces/IBondingRegistry.sol/IBondingRegistry.json (1)

362-374: ABI updates for token getters match the Solidity interface

getLicenseToken / getTicketToken are correctly reflected as no‑arg view functions returning address, and the updated buildInfoId is expected from recompilation; this artifact now lines up with IBondingRegistry.sol and the Rust bindings.

Also applies to: 418-430, 880-880

crates/cli/src/ciphernode/context.rs (1)

19-57: ChainContext wiring and contract bindings look solid

The sol! bindings, provider setup, and helpers (license_token_address, ticket_token_address, ticket_underlying_address, erc20) are cohesive and match the contract ABIs and config model (addresses as strings parsed into alloy::primitives::Address). The artifact paths mirror the established pattern from the evm crate, so the CLI‑side contract access layer looks well‑integrated. Based on learnings, using alloy::primitives::Address here is aligned with existing ciphernode conventions.

Also applies to: 66-136

@hmzakhalid hmzakhalid merged commit 9afdb9d into main Dec 8, 2025
25 checks passed
@github-actions github-actions Bot deleted the feat/cli-commands branch December 16, 2025 02:52
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.

2 participants