feat: Directory Contract#6933
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new directory contract and shared directory types, wires directory addresses through mixnet and client code, implements storage, queries, and transactions for node and curated entries, and updates schemas, tests, configuration, and OpenSpec docs. ChangesDirectory Contract Feature
OpenSpec Documentation
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant NodeOwner
participant MixnetContract
participant DirectoryContract
NodeOwner->>MixnetContract: try_remove_nym_node
MixnetContract->>DirectoryContract: wasm_execute OnNymNodeUnbond(node_id)
DirectoryContract->>DirectoryContract: remove_all_node_entries, subtract digest leaves
DirectoryContract-->>MixnetContract: ack
sequenceDiagram
participant Node
participant DirectoryContract
participant Storage
Node->>DirectoryContract: SetNodeEntry(node_id, label, data, sequence, signature)
DirectoryContract->>DirectoryContract: verify identity signature & sequence
DirectoryContract->>Storage: subtract old leaf, save entry, add new leaf, advance sequence
DirectoryContract-->>Node: Response(SET_NODE_ENTRY event)
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
476397f to
6020327
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tools/internal/localnet-orchestrator/src/orchestrator/setup/cosmwasm_contracts.rs (1)
113-150: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winInstantiate a real directory contract before mixnet init
mixnet_unbondsends a plainwasm_executetostate.directory_contract_address, so the placeholdermixnet_rewarderaddress stored inmixnet_init_messagewill break unbonding unless the orchestrator deploys a real directory contract or rewrites that address before first use.🤖 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 `@tools/internal/localnet-orchestrator/src/orchestrator/setup/cosmwasm_contracts.rs` around lines 113 - 150, The mixnet initialization currently uses placeholder `mixnet_rewarder` addresses in `mixnet_init_message`, which leaves `directory_contract_address` invalid for later `mixnet_unbond` calls. Update `mixnet_init_message` in `cosmwasm_contracts.rs` to populate `directory_contract_address` with the actual directory contract address, or ensure the orchestrator deploys and wires the real directory contract before mixnet instantiation. Verify the value used by `mixnet_unbond` matches the address returned from the setup flow rather than the placeholder.
🧹 Nitpick comments (2)
common/cosmwasm-smart-contracts/directory-contract/src/types.rs (1)
386-407: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win
digest_leafdoesn't guard against key/entry namespace mismatch.
EntryKey::digest_leaf(&self, entry: &DirectoryEntry)accepts anyDirectoryEntryvariant regardless ofself's namespace. The providedstorage.rssnippet shows call sites manually pairingEntryKey::Node { .. }withDirectoryEntry::NodeEntry(..)rather than always going through the safeDirectoryEntryRecord::new_node/new_curatedconstructors. A future refactor that accidentally passes a mismatched variant (e.g.EntryKey::NodewithDirectoryEntry::CuratedEntry) would silently produce a still-valid-looking but semantically wrong leaf, corrupting the on-chain digest without any compile- or run-time signal — a data-integrity risk for a mechanism whose entire purpose is verifiable digest correctness.Consider asserting namespace agreement inside
digest_leaf, or restricting the public entry point toDirectoryEntryRecord::digest_leaf(already namespace-safe by construction).🛡️ Example defensive check
pub fn digest_leaf(&self, entry: &DirectoryEntry) -> Vec<u8> { + debug_assert_eq!( + self.namespace(), + match entry { + DirectoryEntry::NodeEntry(_) => Namespace::Node, + DirectoryEntry::CuratedEntry(_) => Namespace::Curated, + }, + "digest_leaf called with mismatched key namespace and entry variant" + ); let mut buf = vec![self.namespace().tag()];🤖 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 `@common/cosmwasm-smart-contracts/directory-contract/src/types.rs` around lines 386 - 407, `EntryKey::digest_leaf` currently accepts any `DirectoryEntry` and can silently hash mismatched key/value namespaces. Add a namespace/variant check inside `digest_leaf` so `EntryKey::Node` only accepts `DirectoryEntry::NodeEntry` and `EntryKey::Curated` only accepts `DirectoryEntry::CuratedEntry`, and fail loudly on mismatch. If possible, make `DirectoryEntryRecord::digest_leaf` the preferred public path and keep the `EntryKey` helper namespace-safe by construction.contracts/directory/src/transactions.rs (1)
78-163: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
try_set_node_entry/try_delete_node_entrynever validate attached funds.Neither entrypoint accepts
MessageInfo, and per thecontract.rsrouting (try_delete_node_entry(deps, node_id, label, sequence, signature)), no funds check happens anywhere in the call path. Since any relayer can submit these (by design, signature-authorised), an operator who mistakenly attaches coins would have them silently absorbed into the contract with no visible way to recover them. Consider threadinginfothrough and callingcw_utils::nonpayable(&info)?(already a dependency) to reject unexpected funds explicitly.🤖 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 `@contracts/directory/src/transactions.rs` around lines 78 - 163, `try_set_node_entry` and `try_delete_node_entry` currently accept no `MessageInfo`, so they never reject unexpected funds and can silently trap coins. Thread `info` through the call path from the routing in `contract.rs` into both entrypoints, then use `cw_utils::nonpayable(&info)?` at the start of `try_set_node_entry` and `try_delete_node_entry` to explicitly fail on attached funds while leaving the existing signature checks intact.
🤖 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.
Inline comments:
In `@common/cosmwasm-smart-contracts/directory-contract/src/helpers.rs`:
- Around line 19-33: The length-prefix parsing in read_len_prefixed can overflow
on wasm32 when computing the slice end from the u32 prefix. Update
read_len_prefixed to use checked_add when deriving the end offset from the
4-byte header and return DirectoryContractError::MalformedEntryValue if the
addition overflows or if the buffer is still too short, keeping the existing
error path and helper behavior intact.
In `@common/network-defaults/src/network.rs`:
- Around line 46-47: `directory_contract_address` is defined on
`NymNetworkDetails` but not populated from environment variables, so env-based
config always leaves it unset. Add the matching
`with_directory_contract_address` builder to the struct’s fluent API and wire
`get_optional_env(var_names::...)` into `new_from_env()` alongside the existing
`performance_contract_address`, `network_monitors_contract_address`, and
`node_families_contract_address` handling so `DIRECTORY_CONTRACT_ADDRESS` is
honored.
In `@contracts/directory/Cargo.toml`:
- Around line 37-39: Update the stale feature-name comments in the directory
contract manifest so they refer to testable-directory-contract instead of
testable-node-families-contract. Keep the wording aligned with the actual
feature defined in the [features] section and ensure any nearby optional
dependency comments around nym-contracts-common-testing and crate::testing are
corrected consistently.
In `@openspec/changes/archive/2026-07-01-directory-contract/design.md`:
- Line 100: The rollback note is out of date because the mixnet sub-message is
no longer best-effort; update the wording in the design note to reflect that the
mixnet callback is a hard callback and that rollback guidance should assume
failures are not harmless. Adjust the sentence in the archive design document so
it matches the current behavior described by D1 and the push client/read path
fallback story, without changing the rest of the rollback summary.
In `@openspec/changes/archive/2026-07-01-directory-contract/proposal.md`:
- Around line 13-15: The lifecycle bullet in the proposal still describes the
unbond cleanup as best-effort/reply-on-error, which conflicts with the settled
hard callback behavior. Update the wording in the proposal section around the
directory contract lifecycle and unbond handling to reflect the final callback
semantics, or explicitly mark the old text as historical/superseded so it no
longer contradicts the finalized design.
---
Outside diff comments:
In
`@tools/internal/localnet-orchestrator/src/orchestrator/setup/cosmwasm_contracts.rs`:
- Around line 113-150: The mixnet initialization currently uses placeholder
`mixnet_rewarder` addresses in `mixnet_init_message`, which leaves
`directory_contract_address` invalid for later `mixnet_unbond` calls. Update
`mixnet_init_message` in `cosmwasm_contracts.rs` to populate
`directory_contract_address` with the actual directory contract address, or
ensure the orchestrator deploys and wires the real directory contract before
mixnet instantiation. Verify the value used by `mixnet_unbond` matches the
address returned from the setup flow rather than the placeholder.
---
Nitpick comments:
In `@common/cosmwasm-smart-contracts/directory-contract/src/types.rs`:
- Around line 386-407: `EntryKey::digest_leaf` currently accepts any
`DirectoryEntry` and can silently hash mismatched key/value namespaces. Add a
namespace/variant check inside `digest_leaf` so `EntryKey::Node` only accepts
`DirectoryEntry::NodeEntry` and `EntryKey::Curated` only accepts
`DirectoryEntry::CuratedEntry`, and fail loudly on mismatch. If possible, make
`DirectoryEntryRecord::digest_leaf` the preferred public path and keep the
`EntryKey` helper namespace-safe by construction.
In `@contracts/directory/src/transactions.rs`:
- Around line 78-163: `try_set_node_entry` and `try_delete_node_entry` currently
accept no `MessageInfo`, so they never reject unexpected funds and can silently
trap coins. Thread `info` through the call path from the routing in
`contract.rs` into both entrypoints, then use `cw_utils::nonpayable(&info)?` at
the start of `try_set_node_entry` and `try_delete_node_entry` to explicitly fail
on attached funds while leaving the existing signature checks intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6d3a8b80-955f-4d8f-822d-b2927a6bfb11
⛔ Files ignored due to path filters (3)
Cargo.lockis excluded by!**/*.lockcontracts/Cargo.lockis excluded by!**/*.locknym-wallet/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (69)
Cargo.tomlcommon/client-libs/validator-client/Cargo.tomlcommon/client-libs/validator-client/src/nyxd/contract_traits/directory_query_client.rscommon/client-libs/validator-client/src/nyxd/contract_traits/directory_signing_client.rscommon/client-libs/validator-client/src/nyxd/contract_traits/mod.rscommon/client-libs/validator-client/src/nyxd/mod.rscommon/commands/src/validator/cosmwasm/generators/mixnet.rscommon/cosmwasm-smart-contracts/directory-contract/Cargo.tomlcommon/cosmwasm-smart-contracts/directory-contract/src/constants.rscommon/cosmwasm-smart-contracts/directory-contract/src/error.rscommon/cosmwasm-smart-contracts/directory-contract/src/helpers.rscommon/cosmwasm-smart-contracts/directory-contract/src/lib.rscommon/cosmwasm-smart-contracts/directory-contract/src/msg.rscommon/cosmwasm-smart-contracts/directory-contract/src/types.rscommon/cosmwasm-smart-contracts/mixnet-contract/src/msg.rscommon/cosmwasm-smart-contracts/mixnet-contract/src/types.rscommon/lthash/Cargo.tomlcommon/lthash/src/lib.rscommon/network-defaults/src/mainnet.rscommon/network-defaults/src/network.rscommon/network-defaults/src/var_names.rscontracts/Cargo.tomlcontracts/directory/.cargo/configcontracts/directory/Cargo.tomlcontracts/directory/Makefilecontracts/directory/schema/nym-directory-contract.jsoncontracts/directory/schema/raw/execute.jsoncontracts/directory/schema/raw/instantiate.jsoncontracts/directory/schema/raw/migrate.jsoncontracts/directory/schema/raw/query.jsoncontracts/directory/schema/raw/response_to_admin.jsoncontracts/directory/schema/raw/response_to_all_curated_entries.jsoncontracts/directory/schema/raw/response_to_all_entries.jsoncontracts/directory/schema/raw/response_to_allowed_labels.jsoncontracts/directory/schema/raw/response_to_config.jsoncontracts/directory/schema/raw/response_to_curated_entries_paged.jsoncontracts/directory/schema/raw/response_to_curated_entry.jsoncontracts/directory/schema/raw/response_to_digest.jsoncontracts/directory/schema/raw/response_to_node_entries.jsoncontracts/directory/schema/raw/response_to_node_entries_paged.jsoncontracts/directory/schema/raw/response_to_node_entry.jsoncontracts/directory/schema/raw/response_to_sequence.jsoncontracts/directory/src/bin/schema.rscontracts/directory/src/contract.rscontracts/directory/src/lib.rscontracts/directory/src/queries.rscontracts/directory/src/queued_migrations.rscontracts/directory/src/storage.rscontracts/directory/src/testing.rscontracts/directory/src/transactions.rscontracts/mixnet/Cargo.tomlcontracts/mixnet/src/contract.rscontracts/mixnet/src/mixnet_contract_settings/queries.rscontracts/mixnet/src/mixnet_contract_settings/storage.rscontracts/mixnet/src/nodes/transactions.rscontracts/mixnet/src/queued_migrations.rscontracts/mixnet/src/testable_mixnet_contract.rscontracts/node-families/Cargo.tomlcontracts/node-families/src/testing.rscontracts/performance/Cargo.tomlcontracts/performance/src/testing/mod.rsnym-wallet/nym-wallet-types/src/network/sandbox.rsopenspec/changes/archive/2026-07-01-directory-contract/.openspec.yamlopenspec/changes/archive/2026-07-01-directory-contract/design.mdopenspec/changes/archive/2026-07-01-directory-contract/proposal.mdopenspec/changes/archive/2026-07-01-directory-contract/specs/directory-contract/spec.mdopenspec/changes/archive/2026-07-01-directory-contract/tasks.mdopenspec/specs/directory-contract/spec.mdtools/internal/localnet-orchestrator/src/orchestrator/setup/cosmwasm_contracts.rs
da45e15 to
afa8e02
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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.
Inline comments:
In `@contracts/directory/Makefile`:
- Around line 1-5: The helper targets in the Makefile are not marked as phony,
so make may skip them when a same-named file or directory exists. Add a .PHONY
declaration for the wasm and generate-schema targets so they always run, keeping
the existing target names and command bodies unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fd355e59-9acc-42bc-bd43-739ca5014cd5
⛔ Files ignored due to path filters (3)
Cargo.lockis excluded by!**/*.lockcontracts/Cargo.lockis excluded by!**/*.locknym-wallet/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (73)
Cargo.tomlcommon/client-libs/validator-client/Cargo.tomlcommon/client-libs/validator-client/src/nyxd/contract_traits/directory_query_client.rscommon/client-libs/validator-client/src/nyxd/contract_traits/directory_signing_client.rscommon/client-libs/validator-client/src/nyxd/contract_traits/mod.rscommon/client-libs/validator-client/src/nyxd/mod.rscommon/commands/src/validator/cosmwasm/generators/mixnet.rscommon/cosmwasm-smart-contracts/directory-contract/Cargo.tomlcommon/cosmwasm-smart-contracts/directory-contract/src/constants.rscommon/cosmwasm-smart-contracts/directory-contract/src/error.rscommon/cosmwasm-smart-contracts/directory-contract/src/helpers.rscommon/cosmwasm-smart-contracts/directory-contract/src/lib.rscommon/cosmwasm-smart-contracts/directory-contract/src/msg.rscommon/cosmwasm-smart-contracts/directory-contract/src/types.rscommon/cosmwasm-smart-contracts/mixnet-contract/src/msg.rscommon/cosmwasm-smart-contracts/mixnet-contract/src/types.rscommon/lthash/Cargo.tomlcommon/lthash/src/lib.rscommon/network-defaults/src/mainnet.rscommon/network-defaults/src/network.rscommon/network-defaults/src/var_names.rscontracts/Cargo.tomlcontracts/directory/.cargo/configcontracts/directory/Cargo.tomlcontracts/directory/Makefilecontracts/directory/schema/nym-directory-contract.jsoncontracts/directory/schema/raw/execute.jsoncontracts/directory/schema/raw/instantiate.jsoncontracts/directory/schema/raw/migrate.jsoncontracts/directory/schema/raw/query.jsoncontracts/directory/schema/raw/response_to_admin.jsoncontracts/directory/schema/raw/response_to_all_curated_entries.jsoncontracts/directory/schema/raw/response_to_all_entries.jsoncontracts/directory/schema/raw/response_to_allowed_labels.jsoncontracts/directory/schema/raw/response_to_config.jsoncontracts/directory/schema/raw/response_to_curated_entries_paged.jsoncontracts/directory/schema/raw/response_to_curated_entry.jsoncontracts/directory/schema/raw/response_to_digest.jsoncontracts/directory/schema/raw/response_to_node_entries.jsoncontracts/directory/schema/raw/response_to_node_entries_paged.jsoncontracts/directory/schema/raw/response_to_node_entry.jsoncontracts/directory/schema/raw/response_to_sequence.jsoncontracts/directory/src/bin/schema.rscontracts/directory/src/contract.rscontracts/directory/src/lib.rscontracts/directory/src/queries.rscontracts/directory/src/queued_migrations.rscontracts/directory/src/storage.rscontracts/directory/src/testing.rscontracts/directory/src/transactions.rscontracts/mixnet/Cargo.tomlcontracts/mixnet/schema/nym-mixnet-contract.jsoncontracts/mixnet/schema/raw/instantiate.jsoncontracts/mixnet/schema/raw/migrate.jsoncontracts/mixnet/schema/raw/response_to_get_state.jsoncontracts/mixnet/src/contract.rscontracts/mixnet/src/mixnet_contract_settings/queries.rscontracts/mixnet/src/mixnet_contract_settings/storage.rscontracts/mixnet/src/nodes/transactions.rscontracts/mixnet/src/queued_migrations.rscontracts/mixnet/src/testable_mixnet_contract.rscontracts/node-families/Cargo.tomlcontracts/node-families/src/testing.rscontracts/performance/Cargo.tomlcontracts/performance/src/testing/mod.rsnym-wallet/nym-wallet-types/src/network/sandbox.rsopenspec/changes/archive/2026-07-01-directory-contract/.openspec.yamlopenspec/changes/archive/2026-07-01-directory-contract/design.mdopenspec/changes/archive/2026-07-01-directory-contract/proposal.mdopenspec/changes/archive/2026-07-01-directory-contract/specs/directory-contract/spec.mdopenspec/changes/archive/2026-07-01-directory-contract/tasks.mdopenspec/specs/directory-contract/spec.mdtools/internal/localnet-orchestrator/src/orchestrator/setup/cosmwasm_contracts.rs
✅ Files skipped from review due to trivial changes (12)
- contracts/directory/schema/raw/response_to_admin.json
- common/network-defaults/src/var_names.rs
- contracts/mixnet/Cargo.toml
- contracts/directory/src/queued_migrations.rs
- contracts/mixnet/src/mixnet_contract_settings/queries.rs
- contracts/directory/schema/raw/response_to_curated_entries_paged.json
- openspec/changes/archive/2026-07-01-directory-contract/.openspec.yaml
- common/cosmwasm-smart-contracts/directory-contract/src/constants.rs
- contracts/directory/src/lib.rs
- contracts/directory/.cargo/config
- openspec/specs/directory-contract/spec.md
- openspec/changes/archive/2026-07-01-directory-contract/tasks.md
🚧 Files skipped from review as they are similar to previous changes (54)
- common/cosmwasm-smart-contracts/directory-contract/Cargo.toml
- contracts/directory/schema/raw/response_to_node_entries.json
- contracts/directory/schema/raw/migrate.json
- contracts/directory/src/bin/schema.rs
- common/cosmwasm-smart-contracts/directory-contract/src/lib.rs
- contracts/directory/schema/raw/response_to_config.json
- common/cosmwasm-smart-contracts/mixnet-contract/src/types.rs
- common/client-libs/validator-client/Cargo.toml
- contracts/directory/schema/raw/instantiate.json
- common/commands/src/validator/cosmwasm/generators/mixnet.rs
- common/lthash/Cargo.toml
- contracts/directory/schema/raw/response_to_node_entry.json
- contracts/directory/schema/raw/response_to_curated_entry.json
- contracts/mixnet/src/mixnet_contract_settings/storage.rs
- contracts/directory/schema/raw/response_to_sequence.json
- common/cosmwasm-smart-contracts/directory-contract/src/error.rs
- contracts/directory/schema/raw/response_to_allowed_labels.json
- contracts/directory/schema/raw/response_to_all_curated_entries.json
- contracts/directory/Cargo.toml
- common/network-defaults/src/network.rs
- nym-wallet/nym-wallet-types/src/network/sandbox.rs
- common/network-defaults/src/mainnet.rs
- contracts/directory/schema/raw/execute.json
- contracts/directory/schema/raw/response_to_node_entries_paged.json
- tools/internal/localnet-orchestrator/src/orchestrator/setup/cosmwasm_contracts.rs
- contracts/Cargo.toml
- common/cosmwasm-smart-contracts/directory-contract/src/msg.rs
- common/client-libs/validator-client/src/nyxd/contract_traits/directory_signing_client.rs
- contracts/directory/src/queries.rs
- common/client-libs/validator-client/src/nyxd/mod.rs
- common/client-libs/validator-client/src/nyxd/contract_traits/mod.rs
- contracts/mixnet/src/contract.rs
- contracts/node-families/Cargo.toml
- common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs
- contracts/directory/schema/raw/response_to_all_entries.json
- contracts/directory/src/storage.rs
- contracts/performance/Cargo.toml
- contracts/mixnet/src/queued_migrations.rs
- common/client-libs/validator-client/src/nyxd/contract_traits/directory_query_client.rs
- contracts/directory/src/transactions.rs
- common/lthash/src/lib.rs
- openspec/changes/archive/2026-07-01-directory-contract/specs/directory-contract/spec.md
- contracts/directory/schema/raw/response_to_digest.json
- contracts/directory/schema/nym-directory-contract.json
- contracts/mixnet/src/nodes/transactions.rs
- common/cosmwasm-smart-contracts/directory-contract/src/helpers.rs
- common/cosmwasm-smart-contracts/directory-contract/src/types.rs
- contracts/node-families/src/testing.rs
- openspec/changes/archive/2026-07-01-directory-contract/proposal.md
- contracts/performance/src/testing/mod.rs
- contracts/mixnet/src/testable_mixnet_contract.rs
- contracts/directory/src/contract.rs
- contracts/directory/src/testing.rs
- contracts/directory/schema/raw/query.json
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
common/network-defaults/src/network.rs (1)
253-297: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
export_to_envdoesn't exportdirectory_contract_address.
new_from_env()now readsDIRECTORY_CONTRACT_ADDRESS, butexport_to_env()never writes it back out (norPERFORMANCE_CONTRACT_ADDRESS, a pre-existing gap). This breaks round-tripping: exporting aNymNetworkDetailsbuilt withwith_directory_contract(...)to env vars and re-loading vianew_from_env()will silently lose the directory contract address.🔧 Proposed fix
set_optional_var(var_names::COCONUT_DKG_CONTRACT_ADDRESS, self.contracts.coconut_dkg_contract_address); + set_optional_var(var_names::DIRECTORY_CONTRACT_ADDRESS, self.contracts.directory_contract_address);🤖 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 `@common/network-defaults/src/network.rs` around lines 253 - 297, export_to_env is missing round-trip coverage for contract addresses that new_from_env reads back, so update NetworkDetails::export_to_env to also write DIRECTORY_CONTRACT_ADDRESS and the existing PERFORMANCE_CONTRACT_ADDRESS using the same optional export helper pattern used for the other contract fields. Keep the change alongside the current set_optional_var calls in export_to_env so values set via with_directory_contract() are preserved when reloaded through new_from_env().
🤖 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.
Outside diff comments:
In `@common/network-defaults/src/network.rs`:
- Around line 253-297: export_to_env is missing round-trip coverage for contract
addresses that new_from_env reads back, so update NetworkDetails::export_to_env
to also write DIRECTORY_CONTRACT_ADDRESS and the existing
PERFORMANCE_CONTRACT_ADDRESS using the same optional export helper pattern used
for the other contract fields. Keep the change alongside the current
set_optional_var calls in export_to_env so values set via
with_directory_contract() are preserved when reloaded through new_from_env().
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 50bd35d9-313f-4653-82bd-6ee5f260fb92
📒 Files selected for processing (12)
common/network-defaults/src/network.rscontracts/directory/Cargo.tomlcontracts/directory/Makefilecontracts/ecash/Makefilecontracts/mixnet/Makefilecontracts/network-monitors/Makefilecontracts/node-families/Makefilecontracts/nym-pool/Makefilecontracts/performance/Makefilecontracts/vesting/Makefileopenspec/changes/archive/2026-07-01-directory-contract/design.mdopenspec/changes/archive/2026-07-01-directory-contract/proposal.md
✅ Files skipped from review due to trivial changes (2)
- contracts/node-families/Makefile
- openspec/changes/archive/2026-07-01-directory-contract/design.md
🚧 Files skipped from review as they are similar to previous changes (1)
- contracts/directory/Cargo.toml
49d4912 to
118d827
Compare
Summary
Adds a new CosmWasm directory contract: the on-chain source of truth for nym-node configuration. It flips node-info distribution from per-node HTTP pulls to a push model - each nym-node pushes ed25519-signed config (keyed by
(node_id, label)) to the contract, and consumers read it from chain. An incremental on-chain LtHash digest over all entries makes whole-directory retrieval verifiable.Scope here is the contract only. The off-chain retrieval/verification client is a separate future change.
What's included
nym-directory-contract(contracts/directory) + sharednym-directory-contract-commoncrate (msg/types/error/constants/helpers).nym-lthash(common/lthash) - homomorphic multiset hash (LtHash16, 2 KB accumulator, blake3 XOF);cosmwasm-check-verified, MSRV-pinned for the contracts workspace.directory_contract_addressinContractState/InstantiateMsg/MigrateMsg+introduce_directory_contractmigration; the unbond handler notifies the directory (OnNymNodeUnbond) to clean up an unbonded node's entries.DirectoryQueryClient/DirectorySigningClient).Design highlights
(node_id, label, sequence, data). Empty data is rejected on writes, keeping set/delete signature spaces disjoint.Deployment notes
DIRECTORY_CONTRACT_ADDRESSis a placeholder on mainnet (empty) and sandbox - must be set once the contract is deployed. The mixnet migration requires a valid directory address, so deploy the directory contract before migrating the mixnet.Future work
This change is
Summary by CodeRabbit
New Features
Tests / Validation