Skip to content

feat(dojo-world): change manifest format including members for events and models#3370

Merged
glihm merged 3 commits intodojoengine:mainfrom
glihm:fix/manifest-format
Oct 30, 2025
Merged

feat(dojo-world): change manifest format including members for events and models#3370
glihm merged 3 commits intodojoengine:mainfrom
glihm:fix/manifest-format

Conversation

@glihm
Copy link
Collaborator

@glihm glihm commented Oct 30, 2025

This manifest change is backward compatible, and adds correctly the members to events and models.

The format is not having one single abis entry instead of repeated abi keys that were impacting the readability of the manifest.

Summary by CodeRabbit

  • Refactor
    • Centralized ABI collection and sorted serialization in manifests, unifying ABI handling across resources.
  • New Features
    • Resource metadata now includes members derived from ABIs, improving model/event introspection.
  • Chores
    • Policy test data remapped and expanded with updated target entries and methods.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 30, 2025

Walkthrough

Ohayo, sensei! The PR centralizes ABI entries into a Manifest-level abis HashMap (with custom (de)serializers), skips per-entity ABI serialization, derives model/event members from ABIs during local transformation, updates tests to include new ABI fields, and remaps entries in a policies JSON file.

Changes

Cohort / File(s) Summary
Manifest structure and ABI aggregation
crates/dojo/world/src/diff/manifest.rs
Adds abis: HashMap<String, AbiEntry> to Manifest; introduces add_abi_entries, get_abi_name, and custom serialize_abis_hashmap/deserialize_abis_hashmap; aggregates and deduplicates ABI entries from world, contracts, models, events, libraries, and external_contracts during Manifest::new
Per-entity ABI serialization skip
crates/dojo/world/src/diff/manifest.rs
Annotates per-entity abi fields in WorldContract, DojoContract, DojoLibrary, DojoModel, DojoEvent, and ExternalContract with #[serde(skip)] to hide them from serialized output
Entity equality for tests
crates/dojo/world/src/diff/manifest.rs
Adds PartialEq impls for DojoModel and DojoEvent that compare core fields and ABI lengths (instead of full vector equality) to support test assertions
Member derivation from ABI
crates/dojo/world/src/local/artifact_to_local.rs
Adds members_from_abi helper (uses AbiStruct/TypedAbiEvent) and replaces members: vec![] with derived members when building ResourceLocal::Model and ResourceLocal::Event
Test updates for ABI fields
crates/dojo/world/src/contracts/contract_info.rs
Updates test manifests to include per-model abi: vec![] and top-level abis: HashMap::new() in test data construction
Policy remapping
bin/sozo/tests/test_data/policies.json
Wholesale remapping of many policy entries: old target hashes replaced with new target hashes and numerous new target-method pairs added (upgrade, spawn/move/set_enemies/update_, register_, init_contract, etc.)

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Caller as Manifest::new
participant World as WorldClass/Resources
participant Manifest as Manifest(abis)
Note over Caller,Manifest: Initialization & ABI aggregation
Caller->>World: collect world class ABI
Caller->>Manifest: add_abi_entries(world.abi)
Caller->>World: iterate resources (contracts/models/events/libs/ext)
loop per resource
World->>Caller: provide resource with .common.class.abi
Caller->>Manifest: add_abi_entries(resource.abi)
end
Note right of Manifest: deduplicate by name, exclude Impl entries\nstore sorted vector for serialization

mermaid
sequenceDiagram
participant Artifact as artifact_to_local
participant ABI as ABI parser
participant ResourceLocal as ResourceLocal(Model/Event)
Note over Artifact,ResourceLocal: derive members from ABI when building local resources
Artifact->>ABI: ensure_abi() / inspect structs or events
ABI-->>Artifact: AbiStructs / TypedAbiEvent
Artifact->>ResourceLocal: members_from_abi(abi) -> populate members list

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Review areas needing extra attention:
    • crates/dojo/world/src/diff/manifest.rs: ABI aggregation, deduplication logic, and custom (de)serializer correctness (ordering/stability).
    • crates/dojo/world/src/local/artifact_to_local.rs: correctness of members_from_abi mapping (key vs value detection) and event member handling.
    • Tests and PartialEq impls: ensure length-based ABI comparison doesn't hide meaningful differences.
    • bin/sozo/tests/test_data/policies.json: verify remapped targets/methods match intended policy semantics.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.23% 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 "change manifest format including members for events and models" is directly related to the main changes in this pull request. The PR meaningfully addresses two key aspects: restructuring the manifest format (centralizing ABIs into a single abis HashMap instead of repeated per-entity abi fields in manifest.rs) and adding member extraction logic for events and models (in artifact_to_local.rs). The title is clear, concise, and highlights the primary user-facing changes without attempting to document every implementation detail, which aligns with good practice.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent 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 ba2815c and e6eb1e0.

📒 Files selected for processing (1)
  • bin/sozo/tests/test_data/policies.json (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-11-28T23:35:04.367Z
Learnt from: glihm
Repo: dojoengine/dojo PR: 2691
File: bin/sozo/tests/test_data/policies.json:7-32
Timestamp: 2024-11-28T23:35:04.367Z
Learning: The file `bin/sozo/tests/test_data/policies.json` is a test file containing policies used by sessions to determine which methods can be called for which contract addresses. There is not much to verify or check in this file.

Applied to files:

  • bin/sozo/tests/test_data/policies.json
⏰ 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). (1)
  • GitHub Check: fmt
🔇 Additional comments (1)
bin/sozo/tests/test_data/policies.json (1)

1-206: Ohayo sensei, test data update looks solid!

The policies.json file has been updated with new contract address mappings and policy entries, consistent with the manifest format changes. The JSON structure is valid, all target hashes are properly formatted, and method names follow the expected convention.


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

Copy link
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.

Actionable comments posted: 1

📜 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 d6e97ff and ba2815c.

📒 Files selected for processing (3)
  • crates/dojo/world/src/contracts/contract_info.rs (1 hunks)
  • crates/dojo/world/src/diff/manifest.rs (14 hunks)
  • crates/dojo/world/src/local/artifact_to_local.rs (4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-11-05T04:30:12.852Z
Learnt from: glihm
PR: dojoengine/dojo#2633
File: crates/dojo/world/src/contracts/abigen/world.rs:3809-0
Timestamp: 2024-11-05T04:30:12.852Z
Learning: Code in `crates/dojo/world/src/contracts/abigen/` is auto-generated and should be excluded from code reviews.

Applied to files:

  • crates/dojo/world/src/contracts/contract_info.rs
  • crates/dojo/world/src/diff/manifest.rs
🧬 Code graph analysis (3)
crates/dojo/world/src/local/artifact_to_local.rs (1)
crates/dojo/world/src/local/resource.rs (1)
  • abi (175-187)
crates/dojo/world/src/contracts/contract_info.rs (3)
crates/dojo/world/src/local/artifact_to_local.rs (1)
  • abi (98-101)
crates/dojo/world/src/local/resource.rs (1)
  • abi (175-187)
crates/dojo/world/src/diff/manifest.rs (1)
  • new (198-252)
crates/dojo/world/src/diff/manifest.rs (2)
crates/dojo/world/src/local/resource.rs (3)
  • name (130-142)
  • name (271-276)
  • abi (175-187)
crates/dojo/world/src/local/artifact_to_local.rs (1)
  • abi (98-101)
⏰ 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). (1)
  • GitHub Check: fmt

Comment on lines +454 to +523
/// Gets the name of the ABI entry.
fn get_abi_name(abi_entry: &AbiEntry) -> String {
match abi_entry {
AbiEntry::Function(function) => function.name.clone(),
AbiEntry::Event(event) => match event {
AbiEvent::Typed(TypedAbiEvent::Struct(s)) => s.name.clone(),
AbiEvent::Typed(TypedAbiEvent::Enum(e)) => e.name.clone(),
AbiEvent::Untyped(UntypedAbiEvent { name, .. }) => name.clone(),
},
AbiEntry::Struct(struct_) => struct_.name.clone(),
AbiEntry::Enum(enum_) => enum_.name.clone(),
AbiEntry::Constructor(constructor) => constructor.name.clone(),
AbiEntry::Impl(impl_) => impl_.name.clone(),
AbiEntry::Interface(interface) => interface.name.clone(),
AbiEntry::L1Handler(l1_handler) => l1_handler.name.clone(),
}
}

/// Serializes the ABI entries into a vector sorted alphabetically by name.
/// This ensures compatibility with any tool expecting a Cairo contract ABI.
fn serialize_abis_hashmap<S>(
value: &HashMap<String, AbiEntry>,
serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq = serializer.serialize_seq(Some(value.len()))?;

// Sort alphabetically by name.
let mut sorted_entries = value.values().collect::<Vec<_>>();
sorted_entries.sort_by_key(|e| get_abi_name(e));

for abi_entry in sorted_entries {
seq.serialize_element(abi_entry)?;
}

seq.end()
}

/// Deserializes the ABI entries from a vector into a hashmap.
fn deserialize_abis_hashmap<'de, D>(
deserializer: D,
) -> std::result::Result<HashMap<String, AbiEntry>, D::Error>
where
D: serde::Deserializer<'de>,
{
let entries = Vec::<AbiEntry>::deserialize(deserializer)?;

let mut map = HashMap::new();

for abi_entry in entries {
map.insert(get_abi_name(&abi_entry), abi_entry);
}

Ok(map)
}

/// Adds the ABI entries to the manifest, deduplicating them by name.
fn add_abi_entries(abis: &mut HashMap<String, AbiEntry>, abi: Vec<AbiEntry>) {
for abi_entry in abi {
// We can strip out `impl` type entries, since they are not meaningful for the manifest.
// Keeping the interface is enough.
if matches!(abi_entry, AbiEntry::Impl(_)) {
continue;
}

let entry_name = get_abi_name(&abi_entry);
abis.insert(entry_name, abi_entry);
}
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 30, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Ohayo sensei: ABI dedup is clobbering shared function names

Keying the global abis map by get_abi_name means every AbiEntry::Function collapses down to its bare name (e.g. all constructor, upgrade, ensure_abi, etc.). As soon as two different contracts expose a function with the same name, the later add_abi_entries call overwrites the earlier one, so we silently drop ABI entries. Once serialized/deserialized, those contracts have incomplete ABIs and we can’t faithfully reconstruct selectors or entrypoints. Please dedupe with a collision-free key (e.g. include the entry kind plus full path/signature, or store multiple entries per name) so that identically named functions from different contracts survive the merge.

🤖 Prompt for AI Agents
In crates/dojo/world/src/diff/manifest.rs around lines 454 to 523, the global
abis HashMap keyed by get_abi_name causes different contracts' ABI entries with
the same bare name to clobber each other; change the dedup key to be
collision-free. Replace the current String key strategy with either (A) a
composed unique key (e.g. include entry kind and full signature/path:
format!("{}|{}|{}", kind, contract_path_or_type, signature)) by implementing a
new get_abi_key(abi_entry: &AbiEntry) -> String and use it everywhere
get_abi_name is used for map keys, or (B) change the map type to HashMap<String,
Vec<AbiEntry>> and append entries to the vec for a given name (so identical
names from different contracts are preserved) and update serialize_abis_hashmap,
deserialize_abis_hashmap and add_abi_entries accordingly to handle the new
key/value shape; ensure Impl entries are still skipped and adjust
sorting/serialization to produce stable, deterministic output.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It will not happen, since most of the time functions are inside interfaces, which are differently named inherently due to the cairo path of the interface itself.

Copy link
Contributor

Choose a reason for hiding this comment

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

@glihm Ohayo sensei! Thank you for the clarification. That makes perfect sense—since Cairo interfaces include the full path in their name (e.g., dojo::core::IWorldProvider rather than just bare function names), the keying strategy naturally avoids collisions. Functions accessed through different interfaces will have unique names in the abis map because the interface name itself encodes the path.

I appreciate you taking the time to explain this Cairo-specific ABI structure detail! 🙏

🐰✨
(noting this Cairo ABI wisdom for future reviews)


✏️ Learnings added
Learnt from: glihm
Repo: dojoengine/dojo PR: 3370
File: crates/dojo/world/src/diff/manifest.rs:454-523
Timestamp: 2025-10-30T22:20:34.102Z
Learning: In Cairo ABIs, functions are typically inside interfaces whose names include the full Cairo path (e.g., `dojo::core::IWorldProvider`), making interface names inherently unique. When deduplicating ABI entries in Dojo's manifest by name (get_abi_name), collisions don't occur because interface names encode their paths, and Impl entries are intentionally filtered out while keeping interfaces.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: glihm
Repo: dojoengine/dojo PR: 2633
File: crates/dojo/world/src/contracts/abigen/world.rs:3809-0
Timestamp: 2024-11-05T04:30:12.852Z
Learning: Code in `crates/dojo/world/src/contracts/abigen/` is auto-generated and should be excluded from code reviews.

@glihm glihm merged commit 25ce202 into dojoengine:main Oct 30, 2025
10 checks passed
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.

1 participant