Skip to content

feat: add register-contract script to rs-scripts#3744

Open
QuantumExplorer wants to merge 1 commit into
v3.1-devfrom
claude/naughty-curran-0674e6
Open

feat: add register-contract script to rs-scripts#3744
QuantumExplorer wants to merge 1 commit into
v3.1-devfrom
claude/naughty-curran-0674e6

Conversation

@QuantumExplorer
Copy link
Copy Markdown
Member

@QuantumExplorer QuantumExplorer commented May 26, 2026

Issue being fixed or feature implemented

Need a quick CLI for registering data contracts on Platform from local JSON files. Useful for spinning up test contracts on devnet / testnet without writing one-off Rust glue code each time.

What was done?

Adds a new register-contract bin under packages/rs-scripts/:

  • Takes a contract JSON file (e.g. any of the fixtures under packages/rs-drive/tests/supporting_files/contract/), an identity id (base58), and a private key (WIF or 64-char hex).
  • Fetches the identity from Platform via the SDK using a TrustedHttpContextProvider.
  • Walks the identity's public keys and picks the one that matches the supplied private key and satisfies the AUTHENTICATION + CRITICAL + ECDSA_SECP256K1 triple DPP requires on a contract-create signature. If a key matches the private key but doesn't meet the requirement, the error message lists every matched key (purpose / security level / key type / disabled) so the caller can see why nothing was usable.
  • Overrides the JSON's id / ownerId before broadcasting — DataContractCreateTransition::new_from_data_contract regenerates the contract id deterministically from (identity_id, identity_nonce) and sets the owner id anyway, so fixture contracts with hard-coded ids register cleanly.
  • Broadcasts via PutContract::put_to_platform_and_wait_for_response and prints the confirmed contract_id / owner_id / version.

Usage:

cargo run -p rs-scripts --bin register-contract -- \
  -c packages/rs-drive/tests/supporting_files/contract/family/family-contract.json \
  -i HccabTZZpMEDAqU4oQFk3PE47kS6jDDmCjoxR88gFttA \
  -k cTPVy... \
  -a https://52.12.176.90:1443

README.md for rs-scripts updated with full usage docs.

How Has This Been Tested?

  • cargo build -p rs-scripts --bin register-contract — clean.
  • cargo clippy -p rs-scripts --bin register-contract -- -D warnings — clean.
  • cargo fmt --all — clean.
  • cargo run -p rs-scripts --bin register-contract -- --help — clap surface matches the README.

No automated end-to-end run against a live network yet — the script needs a funded identity + a reachable DAPI endpoint. Reusing the SDK's PutContract path means it inherits the SDK's broadcast/wait coverage.

Breaking Changes

None — new binary; no existing API changes.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

Summary by CodeRabbit

  • New Features

    • Added a new CLI command to register Dash Platform data contracts from JSON files. The tool automatically resolves identity keys, configures contract ownership, and broadcasts the registration to the network with support for different network configurations.
  • Documentation

    • Added documentation covering the new contract registration command, including usage examples and configuration options.

Review Change Stack

Adds a new `register-contract` bin under `rs-scripts` that takes a
contract JSON file, an identity id, and a private key (WIF or hex),
fetches the identity from Platform, picks the public key that matches
the supplied private key (and satisfies the AUTHENTICATION + CRITICAL +
ECDSA_SECP256K1 triple DPP requires for a contract-create signature),
overrides the JSON's `id`/`ownerId` so fixture contracts under
`packages/rs-drive/tests/supporting_files/contract/` register correctly,
and broadcasts the `DataContractCreate` state transition via the SDK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added this to the v3.1.0 milestone May 26, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

📝 Walkthrough

Walkthrough

A new register-contract CLI utility is introduced that reads Dash Platform data contract JSON fixtures, resolves identity keys from provided private keys, and broadcasts contract-creation transitions through configured DAPI endpoints. Dependencies and binary target are configured in Cargo.toml, CLI arguments define contract path, identity, private key, and network parameters, and the core implementation orchestrates SDK initialization, identity fetching, key validation, and transition broadcasting.

Changes

register-contract CLI Binary

Layer / File(s) Summary
Binary target and dependency configuration
packages/rs-scripts/Cargo.toml
Adds register-contract binary target pointing to src/bin/register_contract.rs. Expands dependencies with dpp feature flags (json-conversion, state-transition-signing), and new workspace deps (dash-sdk, rs-dapi-client, rs-sdk-trusted-context-provider, simple-signer).
CLI argument parsing and entry point
packages/rs-scripts/src/bin/register_contract.rs
Defines Args struct for contract path, identity ID, private key, DAPI address, and network selection (defaulting to testnet). Implements parse_network to validate network strings, and async Tokio main entrypoint that runs run() and maps errors to exit codes.
Contract registration and key selection
packages/rs-scripts/src/bin/register_contract.rs
Implements run() to parse args, resolve signer from private key, read/parse contract JSON, build SDK context from DAPI, fetch identity, select a signing key matching contract-create requirements (AUTHENTICATION + CRITICAL + ECDSA_SECP256K1, skipping disabled keys), broadcast DataContractCreate transition, and print confirmed contract fields. Implements select_signing_key to iterate and validate identity public keys against signer capabilities and required key constraints.
Usage documentation
packages/rs-scripts/README.md
Documents register-contract script behavior, including identity/key resolution from private key, deterministic contract ID regeneration, owner assignment, CLI usage, full option table, and example invocation registering the family fixture contract.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A contract CLI hops into place,
With DAPI keys at a rapid pace,
Register fixtures with private keys,
Platform transitions reach new highs! 🚀

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding a new register-contract script to the rs-scripts package.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/naughty-curran-0674e6

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.

Copy link
Copy Markdown
Contributor

@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 (1)
packages/rs-scripts/src/bin/register_contract.rs (1)

59-64: 💤 Low value

Consider file-based private key input for improved security.

Passing the private key as a command-line argument exposes it in shell history and process listings. For improved operational security, consider supporting file-based input (e.g., --private-key-file) or reading from stdin when - is passed.

The current approach is acceptable for development/scripting workflows, so this is not a blocker.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/rs-scripts/src/bin/register_contract.rs` around lines 59 - 64, Add a
file/stdin option for supplying the private key to avoid exposing secrets on the
command line: extend the CLI struct (the arg currently named private_key) to
accept either a direct private_key or a new private_key_file: Option<String> (or
change private_key to Option<String>) and add parsing logic where the args are
processed (e.g., in main or the register handler) to prefer private_key_file if
present; if private_key_file == "-" read from stdin, otherwise read the file
contents, trim whitespace/newlines, and use that as the key; if no source
provided, return a clear error. Ensure you reference the existing private_key
symbol and replace usages with the resolved key value after loading from
file/stdin.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/rs-scripts/src/bin/register_contract.rs`:
- Around line 59-64: Add a file/stdin option for supplying the private key to
avoid exposing secrets on the command line: extend the CLI struct (the arg
currently named private_key) to accept either a direct private_key or a new
private_key_file: Option<String> (or change private_key to Option<String>) and
add parsing logic where the args are processed (e.g., in main or the register
handler) to prefer private_key_file if present; if private_key_file == "-" read
from stdin, otherwise read the file contents, trim whitespace/newlines, and use
that as the key; if no source provided, return a clear error. Ensure you
reference the existing private_key symbol and replace usages with the resolved
key value after loading from file/stdin.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3dacc0df-1a50-497c-8845-79f60665071e

📥 Commits

Reviewing files that changed from the base of the PR and between 31e8af2 and 5152624.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • packages/rs-scripts/Cargo.toml
  • packages/rs-scripts/README.md
  • packages/rs-scripts/src/bin/register_contract.rs

@codecov
Copy link
Copy Markdown

codecov Bot commented May 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.31%. Comparing base (31e8af2) to head (5152624).

Additional details and impacted files
@@             Coverage Diff              @@
##           v3.1-dev    #3744      +/-   ##
============================================
+ Coverage     87.16%   87.31%   +0.15%     
============================================
  Files          2607     2590      -17     
  Lines        319420   316913    -2507     
============================================
- Hits         278413   276721    -1692     
+ Misses        41007    40192     -815     
Components Coverage Δ
dpp 87.67% <ø> (-0.01%) ⬇️
drive 85.95% <ø> (ø)
drive-abci 89.60% <ø> (ø)
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.17% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 49.16% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Collaborator

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

The PR’s new register-contract binary is close to usable, but two in-scope correctness issues block it: one documented network mode can never succeed, and the contract JSON is decoded against the local latest protocol rules before the SDK has learned the target network’s real version. The private-key handling is also a real security regression for a tool that explicitly supports mainnet, although that is advisory rather than blocking.

🔴 2 blocking | 🟡 1 suggestion(s)

3 finding(s)

blocking: `regtest` is advertised as a supported network even though this command always aborts on regtest

packages/rs-scripts/src/bin/register_contract.rs (line 70)

This CLI accepts --network regtest in both the clap help and parse_network(), but run() always constructs a TrustedHttpContextProvider for the selected network. That provider rejects Network::Regtest unconditionally in packages/rs-sdk-trusted-context-provider/src/lib.rs:54-56, so every register-contract --network regtest ... invocation fails before any identity lookup or broadcast happens. Because the unsupported mode is introduced and documented by this PR, this is an in-scope user-visible bug that needs to be fixed either by removing regtest from the interface or by using a context provider that actually supports it.

blocking: The contract JSON is parsed with `PlatformVersion::latest()` before the SDK knows the target node’s protocol version

packages/rs-scripts/src/bin/register_contract.rs (line 107)

run() hard-codes let platform_version = PlatformVersion::latest(); and immediately feeds that into DataContract::from_json(...). In packages/rs-dpp/src/data_contract/conversion/json/mod.rs:19-29, that version decides whether the JSON is decoded as DataContractV0 or DataContractV1. The SDK built later is left in auto-detect mode, and its own documentation in packages/rs-sdk/src/sdk.rs:353-365 and 486-491 states that an auto-detect SDK falls back to PlatformVersion::latest() until a proof response has already been parsed successfully. That means this command always interprets the local contract file using the newest contract structure before it has learned the remote network version. This is a concrete compatibility bug, not just a theoretical one: packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v1.rs:15 uses contract_structure_version = 0, while .../v2.rs:15 switches it to 1. On an older network, otherwise valid contract JSON can therefore be rejected or misread before the CLI ever reaches the first request that could teach the SDK the correct version.

suggestion: The signing key is required on the command line, which exposes it through process listings and shell history

packages/rs-scripts/src/bin/register_contract.rs (line 59)

This binary requires the identity private key via --private-key / -k. On Unix-like systems, argv is routinely exposed through ps, /proc, shell history, terminal scrollback, and CI logs, so anyone who can observe the machine while the command runs can recover the key and act as that identity. Because this new CLI explicitly supports mainnet, secret entry should avoid argv exposure and use a safer channel such as an environment variable, stdin, or an interactive hidden prompt.

Inline posting hit GitHub HTTP 422, so I posted the same verified findings as a top-level review body.

Copy link
Copy Markdown
Member Author

@QuantumExplorer QuantumExplorer left a comment

Choose a reason for hiding this comment

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

Self Reviewed

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