Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(torii-indexer): eip 4906 update metadata processor #2984

Merged
merged 20 commits into from
Feb 18, 2025

Conversation

Larkooo
Copy link
Collaborator

@Larkooo Larkooo commented Feb 3, 2025

Summary by CodeRabbit

  • New Features

    • Introduced enhanced NFT metadata updates compliant with the ERC4906 standard, supporting both individual and batch operations.
    • Enabled new external interfaces for streamlined metadata update processing across NFT types.
  • Refactor

    • Streamlined workflows for token registration and metadata retrieval.
    • Improved error handling and modular design, resulting in a more robust and efficient user experience.

Copy link

coderabbitai bot commented Feb 3, 2025

Walkthrough

Ohayo, sensei! This pull request introduces ERC-4906 support by adding new processors for both single and batch metadata updates, extending the event handling capabilities within the indexer engine. It refactors executor and SQLite functionality to improve NFT metadata registration and updating, and enhances spawn-and-move examples with new ERC4906 components and interfaces for emitting metadata events.

Changes

File(s) Change Summary
crates/torii/indexer/src/processors/erc4906_metadata_update.rs
crates/torii/indexer/src/processors/erc4906_batch_metadata_update.rs
crates/torii/indexer/src/processors/mod.rs
Added new ERC4906 processors for handling single and batch metadata updates, including implementations for event identification, validation, task prioritization, and asynchronous processing.
crates/torii/indexer/src/engine.rs Updated the event processor initialization to include the new ERC4906 metadata update processors for ERC721 and ERC1155 contracts.
crates/torii/sqlite/src/executor/erc.rs
crates/torii/sqlite/src/executor/mod.rs
Refactored executor functionality for NFT token registration and metadata updates: renamed fields, introduced UpdateNftMetadataQuery, and added methods (fetch_token_uri, fetch_token_metadata, update_nft_metadata) with streamlined error handling.
crates/torii/sqlite/src/erc.rs Introduced a new public asynchronous method update_nft_metadata and adjusted token identification logic in metadata registration and transfer event handling.
examples/spawn-and-move/src/externals.cairo
examples/spawn-and-move/src/externals/components.cairo
Added new modules (components and submodule erc4906) to expose ERC4906-related functionalities in the spawn-and-move example.
examples/spawn-and-move/src/externals/components/erc4906.cairo Introduced a new ERC4906 interface, component, event types, and their implementations to handle metadata update events.
examples/spawn-and-move/src/externals/erc1155.cairo
examples/spawn-and-move/src/externals/erc721.cairo
Enhanced token modules by integrating the ERC4906Component, updating storage structures, event enums, and external functions to support both single and batch metadata updates.

Sequence Diagram(s)

sequenceDiagram
    participant B as Blockchain Event
    participant E as Engine
    participant P as ERC4906MetadataUpdateProcessor
    participant D as Database/Sql
    B->>E: Emit MetadataUpdate event
    E->>P: Route event to processor
    P->>D: Update NFT metadata record
    D-->>P: Acknowledge update
    P-->>E: Complete processing
Loading
sequenceDiagram
    participant B as Blockchain Event
    participant E as Engine
    participant P as ERC4906BatchMetadataUpdateProcessor
    participant D as Database/Sql
    B->>E: Emit BatchMetadataUpdate event
    E->>P: Route event to processor
    P->>D: Loop: update metadata for each token in range
    D-->>P: Acknowledge each update
    P-->>E: Complete batch processing
Loading

Possibly related PRs

  • test(torii-indexer): add tests for erc tokens  #3033: The changes in the main PR, which introduce the Erc4906MetadataUpdateProcessor for handling ERC-4906 metadata updates, are related to the retrieved PR that adds tests for ERC token operations, as both involve the ERC-4906 standard and its associated functionalities.
  • feat(torii): index whitelisted erc20/erc721 #2494: The changes in the main PR, which introduce the Erc4906MetadataUpdateProcessor for handling ERC-4906 metadata updates, are related to the retrieved PR as both involve the implementation of event processors for managing token metadata updates, specifically focusing on ERC standards.
  • fix(torii): handle failed metadata fetch and empty metadata in db #2755: The changes in the main PR, specifically the introduction of the Erc4906MetadataUpdateProcessor, are related to the modifications in the retrieved PR, which enhances error handling in the process_register_erc721_token_query method, as both involve processing and managing metadata updates for ERC tokens.

Suggested reviewers

  • glihm

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
crates/torii/indexer/src/processors/erc4906_metadata_update.rs (1)

45-66: Task identifier generation is clear, but watch out for collision risk.
Although a DefaultHasher is generally fine, collisions can occur. If collisions become problematic, consider using a more robust hashing approach (e.g., SHA-256).

crates/torii/sqlite/src/executor/erc.rs (1)

236-265: Solid metadata fetching error handling.
The fallback to an empty string if an error occurs is user-friendly. Should you need to differentiate partial vs. total failures, consider logging more details or re-trying.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e823d42 and 5a75b26.

📒 Files selected for processing (3)
  • crates/torii/indexer/src/processors/erc4906_metadata_update.rs (1 hunks)
  • crates/torii/indexer/src/processors/mod.rs (1 hunks)
  • crates/torii/sqlite/src/executor/erc.rs (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • crates/torii/indexer/src/processors/mod.rs
🔇 Additional comments (6)
crates/torii/indexer/src/processors/erc4906_metadata_update.rs (3)

1-11: Ohayo sensei! Imports look organized and consistent.
No issues found with these initial lines, and all dependencies seem necessary.


18-29: Good approach on setting the event key.
Returning "MetadataUpdate" clarifies intent and simplifies subsequent usage. No further adjustments needed.


31-43: Validation logic looks straightforward.
It properly distinguishes single vs. batch metadata updates by checking the event keys count and data emptiness.

crates/torii/sqlite/src/executor/erc.rs (3)

183-234: Fetching token URI is well-structured, sensei!
The fallback to tokenURI is clever, and the warning for both failures is helpful. Just ensure that the empty string fallback won't cause unexpected behaviors downstream.


267-287: Metadata update method looks clean.
Storing metadata based on the newly fetched URI is separated nicely. This improves maintainability.


289-313: Great use of functional decomposition in process_register_erc721_token_query.
The modular approach (fetching separately) streamlines the logic. No major issues here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (7)
crates/torii/indexer/src/processors/erc4906_metadata_update.rs (4)

30-42: Ohayo sensei, consider validating the batch range

In the batch update path (event.keys.len() == 5), you might want to confirm from_token_id <= to_token_id in this validate method to avoid silently skipping or handling invalid ranges.

🧰 Tools
🪛 GitHub Actions: ci

[warning] 33-33: Line exceeds maximum length. Consider breaking the line for better readability.


48-65: Ohayo sensei, consider stronger hashing

If collisions for task_identifier pose a risk, consider using a more robust cryptographic hash (e.g., SHA256) instead of DefaultHasher.

🧰 Tools
🪛 GitHub Actions: ci

[warning] 48-48: Line exceeds maximum length. Consider breaking the line for better readability.


67-116: Ohayo sensei, watch out for large batch loops

If to_token_id - from_token_id is very large, iterating over every token may impact performance. Consider batching or chunk-based database updates.

🧰 Tools
🪛 GitHub Actions: ci

[warning] 80-80: Line exceeds maximum length. Consider breaking the line for better readability.


[warning] 93-93: Line exceeds maximum length. Consider breaking the line for better readability.


33-33: Ohayo sensei, break up lines to satisfy pipeline formatting

The pipeline flags lines 33, 48, 80, and 93 for exceeding the recommended maximum length. Consider splitting them for improved readability:

-if event.keys.len() == 3 && event.data.is_empty() {
+if event.keys.len() == 3
+    && event.data.is_empty() {
  return true;
}

(and similarly for lines 48, 80, and 93)

Also applies to: 48-48, 80-80, 93-93

🧰 Tools
🪛 GitHub Actions: ci

[warning] 33-33: Line exceeds maximum length. Consider breaking the line for better readability.

crates/torii/sqlite/src/erc.rs (1)

146-161: Ohayo sensei, nice straightforward update method

update_erc721_metadata is concise and effective. A small suggestion: adding logs on success or failure might help with debugging and tracing.

crates/torii/sqlite/src/executor/erc.rs (2)

242-271: Ohayo sensei, graceful error fallback

Returning an empty string if the metadata fetch fails keeps the workflow moving. Optionally, you could log or meter repeated failures to spot systemic issues.

🧰 Tools
🪛 GitHub Actions: ci

[warning] 247-247: Line exceeds maximum length. Consider breaking the line for better readability.


247-247: Ohayo sensei, friendly reminder about line length

The pipeline flagged lines 247, 280, 302, and 309 for exceeding the recommended maximum. Splitting them bolsters clarity.

Also applies to: 280-280, 302-302, 309-309

🧰 Tools
🪛 GitHub Actions: ci

[warning] 247-247: Line exceeds maximum length. Consider breaking the line for better readability.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5a75b26 and 605231f.

📒 Files selected for processing (4)
  • crates/torii/indexer/src/processors/erc4906_metadata_update.rs (1 hunks)
  • crates/torii/sqlite/src/erc.rs (2 hunks)
  • crates/torii/sqlite/src/executor/erc.rs (5 hunks)
  • crates/torii/sqlite/src/executor/mod.rs (3 hunks)
🧰 Additional context used
🪛 GitHub Actions: ci
crates/torii/indexer/src/processors/erc4906_metadata_update.rs

[warning] 33-33: Line exceeds maximum length. Consider breaking the line for better readability.


[warning] 48-48: Line exceeds maximum length. Consider breaking the line for better readability.


[warning] 80-80: Line exceeds maximum length. Consider breaking the line for better readability.


[warning] 93-93: Line exceeds maximum length. Consider breaking the line for better readability.

crates/torii/sqlite/src/executor/erc.rs

[warning] 247-247: Line exceeds maximum length. Consider breaking the line for better readability.


[warning] 280-280: Line exceeds maximum length. Consider breaking the line for better readability.


[warning] 302-302: Line exceeds maximum length. Consider breaking the line for better readability.


[warning] 309-309: Line exceeds maximum length. Consider breaking the line for better readability.

🔇 Additional comments (7)
crates/torii/indexer/src/processors/erc4906_metadata_update.rs (2)

25-28: Ohayo sensei, looks good

No issues found with event_key—it neatly identifies the MetadataUpdate event for further processing.


44-46: Ohayo sensei, task_priority seems well-chosen

Keeping this processor at a slightly lower priority than transfer tasks sounds logical.

crates/torii/sqlite/src/executor/erc.rs (3)

48-52: Ohayo sensei, struct definition looks good

UpdateErc721MetadataQuery cleanly encapsulates the needed fields for metadata updates.


189-240: Ohayo sensei, dual-entry-point check is smart

Falling back from token_uri to tokenURI preserves flexibility. The warning and empty value fallback align well with robust error handling.


295-319: Ohayo sensei, cohesive registration flow

The process_register_erc721_token_query neatly pipes through fetch_token_uri and fetch_token_metadata. Implementation looks consistent.

🧰 Tools
🪛 GitHub Actions: ci

[warning] 302-302: Line exceeds maximum length. Consider breaking the line for better readability.


[warning] 309-309: Line exceeds maximum length. Consider breaking the line for better readability.

crates/torii/sqlite/src/executor/mod.rs (2)

119-119: LGTM! Clean enum variant addition.

The new UpdateErc721Metadata variant is well-named and follows the established pattern.


766-775: Ohayo! Clean implementation of metadata update handling, sensei!

The implementation follows the established patterns with proper logging, error handling, and duration tracking.

Comment on lines 273 to 293
pub async fn update_erc721_metadata(
&mut self,
contract_address: Felt,
token_id: U256,
provider: Arc<P>,
) -> Result<()> {
let token_uri = Self::fetch_token_uri(&provider, contract_address, token_id).await?;
let metadata = Self::fetch_token_metadata(contract_address, token_id, &token_uri).await?;

// Update metadata in database
sqlx::query(
"UPDATE tokens SET metadata = ? WHERE contract_address = ? AND id LIKE ?",
)
.bind(&metadata)
.bind(felt_to_sql_string(&contract_address))
.bind(format!("%{}", u256_to_sql_string(&token_id)))
.execute(&mut *self.transaction)
.await?;

Ok(())
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo sensei, consider using an exact match instead of LIKE

Using LIKE '%... may inadvertently update multiple tokens if IDs share a suffix. Switching to an exact match:

- "UPDATE tokens SET metadata = ? WHERE contract_address = ? AND id LIKE ?"
+ "UPDATE tokens SET metadata = ? WHERE contract_address = ? AND id = ?"

...avoids accidental collisions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub async fn update_erc721_metadata(
&mut self,
contract_address: Felt,
token_id: U256,
provider: Arc<P>,
) -> Result<()> {
let token_uri = Self::fetch_token_uri(&provider, contract_address, token_id).await?;
let metadata = Self::fetch_token_metadata(contract_address, token_id, &token_uri).await?;
// Update metadata in database
sqlx::query(
"UPDATE tokens SET metadata = ? WHERE contract_address = ? AND id LIKE ?",
)
.bind(&metadata)
.bind(felt_to_sql_string(&contract_address))
.bind(format!("%{}", u256_to_sql_string(&token_id)))
.execute(&mut *self.transaction)
.await?;
Ok(())
}
pub async fn update_erc721_metadata(
&mut self,
contract_address: Felt,
token_id: U256,
provider: Arc<P>,
) -> Result<()> {
let token_uri = Self::fetch_token_uri(&provider, contract_address, token_id).await?;
let metadata = Self::fetch_token_metadata(contract_address, token_id, &token_uri).await?;
// Update metadata in database
sqlx::query(
"UPDATE tokens SET metadata = ? WHERE contract_address = ? AND id = ?",
)
.bind(&metadata)
.bind(felt_to_sql_string(&contract_address))
.bind(format!("%{}", u256_to_sql_string(&token_id)))
.execute(&mut *self.transaction)
.await?;
Ok(())
}
🧰 Tools
🪛 GitHub Actions: ci

[warning] 280-280: Line exceeds maximum length. Consider breaking the line for better readability.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/torii/indexer/src/processors/erc4906_metadata_update.rs (1)

25-43: Consider using constants for key lengths, sensei!

The validation logic is correct but would be more maintainable with named constants instead of magic numbers.

+    const SINGLE_UPDATE_KEY_LENGTH: usize = 3;
+    const BATCH_UPDATE_KEY_LENGTH: usize = 5;
+
     fn validate(&self, event: &Event) -> bool {
         // Single token metadata update: [hash(MetadataUpdate), token_id.low, token_id.high]
-        if event.keys.len() == 3 && event.data.is_empty() {
+        if event.keys.len() == Self::SINGLE_UPDATE_KEY_LENGTH && event.data.is_empty() {
             return true;
         }
 
         // Batch metadata update: [hash(BatchMetadataUpdate), from_token_id.low, from_token_id.high,
         // to_token_id.low, to_token_id.high]
-        if event.keys.len() == 5 && event.data.is_empty() {
+        if event.keys.len() == Self::BATCH_UPDATE_KEY_LENGTH && event.data.is_empty() {
             return true;
         }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 605231f and 036f04b.

📒 Files selected for processing (4)
  • crates/torii/indexer/src/processors/erc4906_metadata_update.rs (1 hunks)
  • crates/torii/indexer/src/processors/mod.rs (2 hunks)
  • crates/torii/sqlite/src/executor/erc.rs (5 hunks)
  • crates/torii/sqlite/src/executor/mod.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/torii/indexer/src/processors/mod.rs
  • crates/torii/sqlite/src/executor/mod.rs
  • crates/torii/sqlite/src/executor/erc.rs
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: ensure-wasm
  • GitHub Check: docs
  • GitHub Check: clippy
  • GitHub Check: build
🔇 Additional comments (3)
crates/torii/indexer/src/processors/erc4906_metadata_update.rs (3)

1-16: Ohayo sensei! The imports and constants look good!

All necessary dependencies are properly imported and the log target is well-defined.


17-18: The struct declaration is clean and minimal!

Good use of Default and Debug derives for this unit struct.


49-64: Heads up on potential race conditions in batch updates, sensei!

While serializing batch updates by contract address prevents overlapping range issues, it might create a bottleneck if multiple non-overlapping ranges could be processed in parallel. Consider if this level of serialization is necessary.

✅ Verification successful

Ohayo, sensei! Let's get a better look at the context within the file to ensure we're making an informed call on potential race conditions. I'm going to grab more lines around the task_identifier function in crates/torii/indexer/src/processors/erc4906_metadata_update.rs for deeper analysis.


Ohayo, sensei! After checking out the code context in crates/torii/indexer/src/processors/erc4906_metadata_update.rs, it's clear that the design intentionally hashes only the contract address for batch updates. This ensures that batch updates for the same contract are serialized to prevent race conditions from overlapping token ranges. While this does mean that non-overlapping ranges can't be processed concurrently, the current approach is a deliberate trade-off to maintain safety. No changes are needed unless improved parallelism becomes a priority.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any other batch processors that might provide insights
rg -A 5 "batch.*process|process.*batch" --type rust

Length of output: 53


Script:

#!/bin/bash
# Display relevant context around the task_identifier function in the ERC4906 metadata update processor
sed -n '40,80p' crates/torii/indexer/src/processors/erc4906_metadata_update.rs

Length of output: 1353

Copy link

codecov bot commented Feb 3, 2025

Codecov Report

Attention: Patch coverage is 45.58824% with 111 lines in your changes missing coverage. Please review.

Project coverage is 57.69%. Comparing base (1065468) to head (952de8e).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
crates/torii/sqlite/src/executor/erc.rs 62.60% 43 Missing ⚠️
...er/src/processors/erc4906_batch_metadata_update.rs 10.34% 26 Missing ⚠️
.../indexer/src/processors/erc4906_metadata_update.rs 13.04% 20 Missing ⚠️
crates/torii/sqlite/src/erc.rs 47.82% 12 Missing ⚠️
crates/torii/sqlite/src/executor/mod.rs 0.00% 10 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2984      +/-   ##
==========================================
- Coverage   57.76%   57.69%   -0.07%     
==========================================
  Files         437      439       +2     
  Lines       59305    59411     +106     
==========================================
+ Hits        34256    34280      +24     
- Misses      25049    25131      +82     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
crates/torii/sqlite/src/executor/mod.rs (1)

769-779: Consider enhancing error handling for metadata updates.

The implementation looks good sensei, but consider adding more detailed error handling to provide better diagnostics when metadata updates fail.

 QueryType::UpdateErc721Metadata(update_metadata) => {
     debug!(target: LOG_TARGET, "Updating ERC721 metadata.");
     let instant = Instant::now();
-    self.update_erc721_metadata(
-        update_metadata.contract_address,
-        update_metadata.token_id,
-        self.provider.clone(),
-    )
-    .await?;
+    match self.update_erc721_metadata(
+        update_metadata.contract_address,
+        update_metadata.token_id,
+        self.provider.clone(),
+    ).await {
+        Ok(_) => {
+            debug!(target: LOG_TARGET, duration = ?instant.elapsed(), "Updated ERC721 metadata.");
+        }
+        Err(e) => {
+            error!(
+                target: LOG_TARGET,
+                error = %e,
+                contract_address = %update_metadata.contract_address,
+                token_id = %update_metadata.token_id,
+                "Failed to update ERC721 metadata"
+            );
+            return Err(e);
+        }
+    };
-    debug!(target: LOG_TARGET, duration = ?instant.elapsed(), "Updated ERC721 metadata.");
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 18c0083 and fc928bd.

📒 Files selected for processing (2)
  • crates/torii/sqlite/src/executor/erc.rs (8 hunks)
  • crates/torii/sqlite/src/executor/mod.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/torii/sqlite/src/executor/erc.rs
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: clippy
  • GitHub Check: build
  • GitHub Check: docs
🔇 Additional comments (2)
crates/torii/sqlite/src/executor/mod.rs (2)

10-10: LGTM!

Ohayo! The import is well-organized with other erc-related imports.


120-120: LGTM!

The new query type follows the established pattern and is well-integrated into the enum.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
crates/torii/sqlite/src/executor/erc.rs (3)

338-412: Ohayo sensei, consider enhancing error logging.

While the method is robust in trying multiple entry points, it could benefit from more detailed error logging to help with debugging.

Consider adding specific error messages for each failed attempt:

 } else {
+    let token_uri_err = provider.call(/* token_uri call */).await.err();
+    let tokenURI_err = provider.call(/* tokenURI call */).await.err();
+    let uri_err = provider.call(/* uri call */).await.err();
     warn!(
         contract_address = format!("{:#x}", contract_address),
         token_id = %token_id,
+        token_uri_error = ?token_uri_err,
+        tokenURI_error = ?tokenURI_err,
+        uri_error = ?uri_err,
         "Error fetching token URI, empty metadata will be used instead.",
     );

414-438: Consider adding metadata caching.

To improve performance and reduce network calls, consider caching the fetched metadata.

This could be particularly beneficial for frequently accessed tokens or when the same metadata URL is used by multiple tokens (common in ERC-1155).


440-457: Consider implementing optimistic updates.

To improve user experience, consider implementing optimistic updates through the SimpleBroker.

Add broker message dispatch:

     .execute(&mut *self.transaction)
     .await?;

+    // Publish optimistic update
+    if let Ok(token) = sqlx::query_as::<_, Token>("SELECT * FROM tokens WHERE id = ?")
+        .bind(felt_and_u256_to_sql_string(&contract_address, &token_id))
+        .fetch_one(&mut *self.transaction)
+        .await
+    {
+        SimpleBroker::publish(unsafe {
+            std::mem::transmute::<Token, OptimisticToken>(token.clone())
+        });
+    }
crates/torii/sqlite/src/executor/mod.rs (1)

757-767: Enhance logging for better observability.

Consider adding more detailed logging to help with monitoring and debugging.

Add more context to the logs:

-    debug!(target: LOG_TARGET, "Updating ERC721 metadata.");
+    debug!(
+        target: LOG_TARGET,
+        contract_address = format!("{:#x}", update_metadata.contract_address),
+        token_id = %update_metadata.token_id,
+        "Updating ERC721 metadata"
+    );
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d9b2762 and 2fa1ed7.

📒 Files selected for processing (4)
  • crates/torii/indexer/src/processors/mod.rs (2 hunks)
  • crates/torii/sqlite/src/erc.rs (5 hunks)
  • crates/torii/sqlite/src/executor/erc.rs (4 hunks)
  • crates/torii/sqlite/src/executor/mod.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/torii/indexer/src/processors/mod.rs
🧰 Additional context used
🪛 GitHub Actions: ci
crates/torii/sqlite/src/erc.rs

[error] 10-10: Rust formatting check failed. Multiple imports should be grouped together.


[error] 150-150: Rust formatting check failed. The UpdateNftMetadataQuery instantiation should be formatted on a single line.

🔇 Additional comments (4)
crates/torii/sqlite/src/erc.rs (2)

95-100: LGTM! Improved token ID handling.

The changes standardize token ID generation using felt_and_u256_to_sql_string, making the code more consistent and maintainable.

Also applies to: 107-107


242-243: LGTM! Consistent parameter usage.

The method now consistently uses the id parameter throughout, improving code clarity and maintainability.

Also applies to: 250-251, 260-260

crates/torii/sqlite/src/executor/erc.rs (1)

40-44: LGTM! Well-structured query type.

The UpdateNftMetadataQuery struct is cleanly defined with appropriate fields for contract address and token ID.

crates/torii/sqlite/src/executor/mod.rs (1)

121-121: LGTM! Clean enum extension.

The new UpdateNftMetadata variant follows the existing pattern and is well-placed in the enum.

Comment on lines 145 to 160
pub async fn update_nft_metadata(
&mut self,
contract_address: Felt,
token_id: U256,
) -> Result<()> {
self.executor.send(QueryMessage::new(
"".to_string(),
vec![],
QueryType::UpdateNftMetadata(UpdateNftMetadataQuery {
contract_address,
token_id,
}),
))?;

Ok(())
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo sensei, let's fix the query formatting.

The UpdateNftMetadataQuery instantiation should be formatted on a single line.

Apply this diff to fix the formatting:

-        QueryType::UpdateNftMetadata(UpdateNftMetadataQuery {
-            contract_address,
-            token_id,
-        }),
+        QueryType::UpdateNftMetadata(UpdateNftMetadataQuery { contract_address, token_id }),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub async fn update_nft_metadata(
&mut self,
contract_address: Felt,
token_id: U256,
) -> Result<()> {
self.executor.send(QueryMessage::new(
"".to_string(),
vec![],
QueryType::UpdateNftMetadata(UpdateNftMetadataQuery {
contract_address,
token_id,
}),
))?;
Ok(())
}
pub async fn update_nft_metadata(
&mut self,
contract_address: Felt,
token_id: U256,
) -> Result<()> {
self.executor.send(QueryMessage::new(
"".to_string(),
vec![],
QueryType::UpdateNftMetadata(UpdateNftMetadataQuery { contract_address, token_id }),
))?;
Ok(())
}
🧰 Tools
🪛 GitHub Actions: ci

[error] 150-150: Rust formatting check failed. The UpdateNftMetadataQuery instantiation should be formatted on a single line.

@@ -10,6 +10,7 @@
use super::utils::{u256_to_sql_string, I256};
use super::{Sql, SQL_FELT_DELIMITER};
use crate::constants::TOKEN_TRANSFER_TABLE;
use crate::executor::erc::UpdateNftMetadataQuery;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ohayo sensei, let's group related imports together.

The import for UpdateNftMetadataQuery should be grouped with other imports from the executor module.

Apply this diff to fix the formatting:

-use crate::executor::erc::UpdateNftMetadataQuery;
 use crate::executor::erc::RegisterNftTokenQuery;
+use crate::executor::erc::{RegisterNftTokenQuery, UpdateNftMetadataQuery};

Committable suggestion skipped: line range outside the PR's diff.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
crates/torii/sqlite/src/erc.rs (1)

144-156: Ohayo sensei! Let's improve the query message construction.

The empty string and empty vector arguments seem unnecessary for this query type.

Apply this diff to simplify the query message construction:

-        self.executor.send(QueryMessage::new(
-            "".to_string(),
-            vec![],
-            QueryType::UpdateNftMetadata(UpdateNftMetadataQuery { contract_address, token_id }),
-        ))?;
+        self.executor.send(QueryMessage::new_simple(
+            QueryType::UpdateNftMetadata(UpdateNftMetadataQuery { contract_address, token_id })
+        ))?;

Note: This assumes the existence of a new_simple constructor. If it doesn't exist, we could create one to handle cases where only the query type is needed.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22fd5e9 and 09923f1.

📒 Files selected for processing (1)
  • crates/torii/sqlite/src/erc.rs (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: clippy
  • GitHub Check: ensure-wasm
  • GitHub Check: docs
🔇 Additional comments (3)
crates/torii/sqlite/src/erc.rs (3)

13-13: Ohayo sensei! The imports look good.

The imports are correctly organized and grouped together.


94-99: Ohayo sensei! The NFT transfer handling looks good.

The changes improve consistency by using a standardized token ID format throughout the method.

Also applies to: 106-106


238-238: Ohayo sensei! The parameter renaming looks good.

The changes improve naming consistency throughout the codebase.

Also applies to: 246-246, 256-256

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
examples/spawn-and-move/src/externals/erc721.cairo (1)

75-112: Ohayo sensei, the new metadata update externals look solid.
Enforcing assert_only_owner fosters security. Emitting separate events for single, batch, and multiple tokens provides needed flexibility. Make sure to thoroughly test these flows to confirm no corner cases (e.g., empty arrays) break the loop or validations.

🧰 Tools
🪛 GitHub Actions: ci

[error] 76-76: Formatting check failed. Ensure there is a newline at the end of the file.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09923f1 and 9aa1b44.

📒 Files selected for processing (5)
  • examples/spawn-and-move/src/externals.cairo (1 hunks)
  • examples/spawn-and-move/src/externals/components.cairo (1 hunks)
  • examples/spawn-and-move/src/externals/components/erc4906.cairo (1 hunks)
  • examples/spawn-and-move/src/externals/erc1155.cairo (4 hunks)
  • examples/spawn-and-move/src/externals/erc721.cairo (4 hunks)
✅ Files skipped from review due to trivial changes (2)
  • examples/spawn-and-move/src/externals/components.cairo
  • examples/spawn-and-move/src/externals.cairo
🧰 Additional context used
🪛 GitHub Actions: ci
examples/spawn-and-move/src/externals/components/erc4906.cairo

[error] 34-34: Formatting check failed. Ensure there is a newline at the end of the file.

examples/spawn-and-move/src/externals/erc1155.cairo

[error] 106-106: Formatting check failed. Ensure there is a newline at the end of the file.

examples/spawn-and-move/src/externals/erc721.cairo

[error] 76-76: Formatting check failed. Ensure there is a newline at the end of the file.

🔇 Additional comments (10)
examples/spawn-and-move/src/externals/components/erc4906.cairo (3)

1-5: Ohayo sensei, the trait design looks clear and minimal.
This concise interface is straightforward and effectively outlines the two essential functions for metadata updates.


14-19: Ohayo sensei, event enumeration structure looks good.
Defining two event types with an explicit #[event] annotation helps keep them self-descriptive and distinct.


35-57: Ohayo sensei, the component implementation is consistent.
Using emit_... methods for each event is a tidy approach that cleanly segregates logic. The assert usage in line 50 is direct and effectively ensures valid token ID ranges.

examples/spawn-and-move/src/externals/erc721.cairo (3)

10-15: Ohayo sensei, great addition of the ERC4906 component.
Importing and declaring ERC4906Component as a new component enhances metadata flexibility for ERC-721 tokens without cluttering the existing code.

Also applies to: 22-23


37-38: Ohayo sensei, substorage setup is coherent.
Adding erc4906 to the storage ensures all ERC4906-related state remains isolated and organized.


50-51: Ohayo sensei, enumerating ERC4906 events aligns the contract’s event flow.
Flattening these events helps external processors receive consistent logs. Nicely done!

examples/spawn-and-move/src/externals/erc1155.cairo (4)

10-15: Ohayo sensei, the ERC4906 integration is consistent.
Similar to ERC-721, embedding ERC4906Component here paves the way for cross-standard metadata updates.

Also applies to: 22-23


37-38: Ohayo sensei, substorage mapping maintains clarity.
Keeping each component’s storage separate is a neat approach for better code organization and maintainability.


50-51: Ohayo sensei, integrating ERC4906 events into the master event enum is well-executed.
Consistent event flattening ensures downstream tooling sees all events in a uniform manner.


105-142: Ohayo sensei, the new token metadata update functions look robust and consistent with ownership checks.
The logic to loop over an array of token IDs ensures flexible updates, while also preserving the single-token and range-based updates. Good coverage!

🧰 Tools
🪛 GitHub Actions: ci

[error] 106-106: Formatting check failed. Ensure there is a newline at the end of the file.

#[key]
token_id: u256,
}

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add a newline at the end of the file.
The pipeline complains about formatting on line 34, indicating there's no trailing newline. Fixing this is required to pass CI.

 ... end of file ...
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// ... (existing file content remains unchanged)
🧰 Tools
🪛 GitHub Actions: ci

[error] 34-34: Formatting check failed. Ensure there is a newline at the end of the file.

@@ -63,5 +71,43 @@ mod ERC721Token {
fn mint(ref self: ContractState, token_id: u256) {
self.erc721.mint(starknet::get_caller_address(), token_id);
}

#[external(v0)]
fn update_token_metadata(ref self: ContractState, token_id: u256) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add a newline at the end of the file.
The pipeline highlights a formatting check failure at line 76. Ensure there’s exactly one trailing newline to pass CI.

 ... end of file ...
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn update_token_metadata(ref self: ContractState, token_id: u256) {
fn update_token_metadata(ref self: ContractState, token_id: u256) {
}
🧰 Tools
🪛 GitHub Actions: ci

[error] 76-76: Formatting check failed. Ensure there is a newline at the end of the file.

@@ -93,5 +101,44 @@ mod ERC1155Token {
// Seems to not be supported by default dojo account.
// self.erc1155.batch_mint_with_acceptance_check(account, token_ids, values, data);
}

#[external(v0)]
fn update_token_metadata(ref self: ContractState, token_id: u256) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add a newline at the end of the file.
The formatting error at line 106 indicates no trailing newline is present. Adding it will resolve the pipeline failure.

 ... end of file ...
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn update_token_metadata(ref self: ContractState, token_id: u256) {
fn update_token_metadata(ref self: ContractState, token_id: u256) {
}
🧰 Tools
🪛 GitHub Actions: ci

[error] 106-106: Formatting check failed. Ensure there is a newline at the end of the file.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
crates/torii/indexer/src/processors/erc4906_metadata_update_batch.rs (2)

27-31: Ohayo sensei, consider thorough error logging in validation.

While limiting the event to exactly five keys with no data is correct per ERC-4906, it might be helpful to log an explicit error if the event fails validation, providing clearer debugging info.


59-62: Ohayo sensei, beware of large token ranges in the loop.

Looping from from_token_id to to_token_id could be costly if the range is large. Consider introducing safeguards or batching to avoid long-running tasks or massive DB writes.

crates/torii/sqlite/src/executor/erc.rs (2)

334-409: Ohayo sensei, consider strengthening error-handling or fallback logic.

When calling the fallback entry points (token_uri, tokenURI, uri), you rely on the last successful call or an empty string if all fail. For better resilience, consider logging or distinguishing which call succeeded or failed.


437-454: Ohayo sensei, nice direct update query!

update_erc721_metadata uses an exact match on id in the UPDATE tokens query. This approach avoids collisions that can arise from wildcard usage. Also, handle potential network or parsing failures by verifying partial updates don’t leave you in an inconsistent state.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9aa1b44 and 49215fa.

📒 Files selected for processing (4)
  • crates/torii/indexer/src/processors/erc4906_metadata_update.rs (1 hunks)
  • crates/torii/indexer/src/processors/erc4906_metadata_update_batch.rs (1 hunks)
  • crates/torii/indexer/src/processors/mod.rs (2 hunks)
  • crates/torii/sqlite/src/executor/erc.rs (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/torii/indexer/src/processors/mod.rs
  • crates/torii/indexer/src/processors/erc4906_metadata_update.rs
🧰 Additional context used
🪛 GitHub Actions: ci
crates/torii/indexer/src/processors/erc4906_metadata_update_batch.rs

[error] 72-72: Rust formatting check failed. Please run 'rustfmt' to format the code.

🔇 Additional comments (6)
crates/torii/indexer/src/processors/erc4906_metadata_update_batch.rs (2)

15-17: Ohayo sensei, nice dedicated struct for the processor!

Defining Erc4906BatchMetadataUpdateProcessor in its own struct nicely encapsulates the batch metadata update logic. This approach aids readability and future expansions for ERC-4906.


72-72: Ohayo sensei, please fix the Rust formatting issue.

Rustfmt is failing on line 72. Running cargo fmt or rustfmt locally should resolve this pipeline failure.

🧰 Tools
🪛 GitHub Actions: ci

[error] 72-72: Rust formatting check failed. Please run 'rustfmt' to format the code.

crates/torii/sqlite/src/executor/erc.rs (4)

21-22: Ohayo sensei, thanks for centralizing these conversions!

Bundling conversions (e.g. felt_and_u256_to_sql_string and sql_string_to_u256) in the utils fosters consistency and prevents scattered inline conversions across the codebase.


40-44: Ohayo sensei, this new struct addition is clean and straightforward.

UpdateNftMetadataQuery neatly packages the NFT metadata update requirements. This ensures clarity when passing these details around.


216-229: Ohayo sensei, great reusability!

Using the new fetch_token_uri and fetch_token_metadata methods in process_register_nft_token_query lowers duplication and promotes code cleanliness.


411-435: Ohayo sensei, nicely isolated metadata fetch approach.

fetch_token_metadata cleanly separates remote or data-URI retrieval from the rest of the logic. Just mind potential large metadata payloads or malformed JSON structures.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/torii/sqlite/src/executor/erc.rs (1)

411-435: Consider caching failed metadata fetches.

To prevent repeated failed requests for the same token URI, consider implementing a temporary cache for failed fetches.

+use std::collections::HashSet;
+use std::sync::Mutex;
+
+lazy_static! {
+    static ref FAILED_URIS: Mutex<HashSet<String>> = Mutex::new(HashSet::new());
+}
+
 async fn fetch_token_metadata(
     contract_address: Felt,
     token_id: U256,
     token_uri: &str,
 ) -> Result<String> {
     if token_uri.is_empty() {
         return Ok("".to_string());
     }
+
+    // Check if URI is in failed cache
+    if FAILED_URIS.lock().unwrap().contains(token_uri) {
+        return Ok("".to_string());
+    }

     let metadata = Self::fetch_metadata(token_uri).await;
     match metadata {
         Ok(metadata) => {
             serde_json::to_string(&metadata).context("Failed to serialize metadata")
         }
         Err(_) => {
+            // Cache failed URI
+            FAILED_URIS.lock().unwrap().insert(token_uri.to_string());
             warn!(
                 contract_address = format!("{:#x}", contract_address),
                 token_id = %token_id,
                 token_uri = %token_uri,
                 "Error fetching metadata, empty metadata will be used instead.",
             );
             Ok("".to_string())
         }
     }
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49215fa and 588bec1.

📒 Files selected for processing (7)
  • crates/torii/indexer/src/engine.rs (2 hunks)
  • crates/torii/indexer/src/processors/erc4906_batch_metadata_update.rs (1 hunks)
  • crates/torii/indexer/src/processors/erc4906_metadata_update.rs (1 hunks)
  • crates/torii/indexer/src/processors/mod.rs (2 hunks)
  • crates/torii/sqlite/src/erc.rs (5 hunks)
  • crates/torii/sqlite/src/executor/erc.rs (8 hunks)
  • crates/torii/sqlite/src/executor/mod.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/torii/indexer/src/processors/mod.rs
  • crates/torii/indexer/src/processors/erc4906_metadata_update.rs
  • crates/torii/indexer/src/engine.rs
🔇 Additional comments (7)
crates/torii/indexer/src/processors/erc4906_batch_metadata_update.rs (4)

23-25: LGTM! Event key matches ERC-4906 specification.

The event key correctly matches the ERC-4906 BatchMetadataUpdate event name.


27-31: LGTM! Validation matches ERC-4906 event structure.

The validation correctly checks for the expected BatchMetadataUpdate event structure with 5 keys (event hash + token ID ranges) and empty data.


33-35: LGTM! Appropriate task priority.

Priority level 2 is suitable for metadata updates, allowing them to proceed without blocking critical operations.


37-39: LGTM! Sequential processing ensures ordered updates.

Using TASK_ID_SEQUENTIAL ensures batch updates are processed in order, maintaining data consistency.

crates/torii/sqlite/src/erc.rs (1)

141-153: LGTM! Clean implementation of NFT metadata update.

The update_nft_metadata method is well-structured and follows the codebase's patterns for database operations.

crates/torii/sqlite/src/executor/erc.rs (1)

335-409: LGTM! Robust token URI fetching implementation.

The fetch_token_uri implementation:

  1. Tries multiple entry point names (token_uri, tokenURI, uri)
  2. Handles both ByteArray and Array return types
  3. Includes helpful debug logging
  4. Gracefully handles failures
crates/torii/sqlite/src/executor/mod.rs (1)

757-767: LGTM! Clean integration of NFT metadata updates.

The UpdateNftMetadata query type is well-integrated into the existing query handling system with appropriate logging and error handling.

Comment on lines +41 to +73
async fn process(
&self,
_world: &WorldContractReader<P>,
db: &mut Sql,
_block_number: u64,
_block_timestamp: u64,
_event_id: &str,
event: &Event,
_config: &EventProcessorConfig,
) -> Result<(), Error> {
let token_address = event.from_address;
let from_token_id = U256Cainome::cairo_deserialize(&event.keys, 1)?;
let from_token_id = U256::from_words(from_token_id.low, from_token_id.high);

let to_token_id = U256Cainome::cairo_deserialize(&event.keys, 3)?;
let to_token_id = U256::from_words(to_token_id.low, to_token_id.high);

let mut token_id = from_token_id;
while token_id <= to_token_id {
db.update_nft_metadata(token_address, token_id).await?;
token_id += U256::from(1u8);
}

debug!(
target: LOG_TARGET,
token_address = ?token_address,
from_token_id = ?from_token_id,
to_token_id = ?to_token_id,
"NFT metadata updated for token range"
);

Ok(())
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ohayo sensei! Consider adding range size limits.

The batch update processor doesn't limit the token ID range size. Large ranges could:

  1. Cause excessive database operations
  2. Lead to timeouts or resource exhaustion
  3. Impact system performance

Consider adding a reasonable maximum range size (e.g., 1000 tokens).

 async fn process(
     &self,
     _world: &WorldContractReader<P>,
     db: &mut Sql,
     _block_number: u64,
     _block_timestamp: u64,
     _event_id: &str,
     event: &Event,
     _config: &EventProcessorConfig,
 ) -> Result<(), Error> {
     let token_address = event.from_address;
     let from_token_id = U256Cainome::cairo_deserialize(&event.keys, 1)?;
     let from_token_id = U256::from_words(from_token_id.low, from_token_id.high);

     let to_token_id = U256Cainome::cairo_deserialize(&event.keys, 3)?;
     let to_token_id = U256::from_words(to_token_id.low, to_token_id.high);

+    // Limit maximum range size to prevent resource exhaustion
+    const MAX_RANGE_SIZE: U256 = U256::from(1000u32);
+    if to_token_id - from_token_id > MAX_RANGE_SIZE {
+        return Err(anyhow::anyhow!(
+            "Token ID range too large. Maximum allowed: {}", MAX_RANGE_SIZE
+        ));
+    }

     let mut token_id = from_token_id;
     while token_id <= to_token_id {
         db.update_nft_metadata(token_address, token_id).await?;
         token_id += U256::from(1u8);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async fn process(
&self,
_world: &WorldContractReader<P>,
db: &mut Sql,
_block_number: u64,
_block_timestamp: u64,
_event_id: &str,
event: &Event,
_config: &EventProcessorConfig,
) -> Result<(), Error> {
let token_address = event.from_address;
let from_token_id = U256Cainome::cairo_deserialize(&event.keys, 1)?;
let from_token_id = U256::from_words(from_token_id.low, from_token_id.high);
let to_token_id = U256Cainome::cairo_deserialize(&event.keys, 3)?;
let to_token_id = U256::from_words(to_token_id.low, to_token_id.high);
let mut token_id = from_token_id;
while token_id <= to_token_id {
db.update_nft_metadata(token_address, token_id).await?;
token_id += U256::from(1u8);
}
debug!(
target: LOG_TARGET,
token_address = ?token_address,
from_token_id = ?from_token_id,
to_token_id = ?to_token_id,
"NFT metadata updated for token range"
);
Ok(())
}
async fn process(
&self,
_world: &WorldContractReader<P>,
db: &mut Sql,
_block_number: u64,
_block_timestamp: u64,
_event_id: &str,
event: &Event,
_config: &EventProcessorConfig,
) -> Result<(), Error> {
let token_address = event.from_address;
let from_token_id = U256Cainome::cairo_deserialize(&event.keys, 1)?;
let from_token_id = U256::from_words(from_token_id.low, from_token_id.high);
let to_token_id = U256Cainome::cairo_deserialize(&event.keys, 3)?;
let to_token_id = U256::from_words(to_token_id.low, to_token_id.high);
// Limit maximum range size to prevent resource exhaustion
const MAX_RANGE_SIZE: U256 = U256::from(1000u32);
if to_token_id - from_token_id > MAX_RANGE_SIZE {
return Err(anyhow::anyhow!(
"Token ID range too large. Maximum allowed: {}",
MAX_RANGE_SIZE
));
}
let mut token_id = from_token_id;
while token_id <= to_token_id {
db.update_nft_metadata(token_address, token_id).await?;
token_id += U256::from(1u8);
}
debug!(
target: LOG_TARGET,
token_address = ?token_address,
from_token_id = ?from_token_id,
to_token_id = ?to_token_id,
"NFT metadata updated for token range"
);
Ok(())
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
examples/spawn-and-move/src/externals/erc721.cairo (1)

95-109: Consider using array iteration methods, sensei!

The loop implementation could be simplified using array iteration methods. Also, consider adding a check for empty token_ids array.

-        let mut i: usize = 0;
-        loop {
-            if i >= token_ids.len() {
-                break;
-            }
-            self.erc4906.emit_metadata_update(*token_ids.at(i));
-            i += 1;
-        }
+        assert(token_ids.len() > 0, 'Empty token_ids');
+        token_ids.iter().for_each(|token_id| {
+            self.erc4906.emit_metadata_update(*token_id);
+        });
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 588bec1 and 952de8e.

⛔ Files ignored due to path filters (2)
  • spawn-and-move-db.tar.gz is excluded by !**/*.gz
  • types-test-db.tar.gz is excluded by !**/*.gz
📒 Files selected for processing (5)
  • examples/spawn-and-move/src/externals.cairo (1 hunks)
  • examples/spawn-and-move/src/externals/components.cairo (1 hunks)
  • examples/spawn-and-move/src/externals/components/erc4906.cairo (1 hunks)
  • examples/spawn-and-move/src/externals/erc1155.cairo (4 hunks)
  • examples/spawn-and-move/src/externals/erc721.cairo (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • examples/spawn-and-move/src/externals.cairo
  • examples/spawn-and-move/src/externals/components.cairo
  • examples/spawn-and-move/src/externals/components/erc4906.cairo
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: docs
  • GitHub Check: build
  • GitHub Check: ensure-wasm
  • GitHub Check: clippy
🔇 Additional comments (3)
examples/spawn-and-move/src/externals/erc721.cairo (2)

10-15: Ohayo sensei! Clean component integration!

The ERC4906 component is integrated following the same pattern as other components, maintaining consistency.


22-23: Implementation looks great, sensei!

The ERC4906MixinImpl is properly implemented with the correct attributes.

examples/spawn-and-move/src/externals/erc1155.cairo (1)

125-140: Same array iteration improvement applies here, sensei!

Consider the same array iteration improvement as suggested for the ERC721 implementation.

Comment on lines +75 to +82
#[external(v0)]
fn update_token_metadata(ref self: ContractState, token_id: u256) {
// Only owner can update metadata
self.ownable.assert_only_owner();

// Emit metadata update event
self.erc4906.emit_metadata_update(token_id);
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Ohayo! Consider adding metadata validation, sensei!

The function emits the event but doesn't verify if the token exists. Consider adding a check to ensure the token exists before emitting the update event.


🏁 Script executed:

#!/bin/bash
# Search for token existence checks in similar functions
ast-grep --pattern 'fn $FUNC($_, token_id: u256) {
  $$$
  self.erc721._exists(token_id)
  $$$
}'

Length of output: 99


Ohayo sensei – Token Existence Check Needed!
We've re-run our searches (using ast-grep and rg) and found no evidence of token existence checks (i.e. calls to self.erc721._exists(token_id)) in similar metadata update functions. This confirms that the function:

        #[external(v0)]
        fn update_token_metadata(ref self: ContractState, token_id: u256) {
            // Only owner can update metadata
            self.ownable.assert_only_owner();

            // Emit metadata update event
            self.erc4906.emit_metadata_update(token_id);
        }

does indeed emit the metadata update event without verifying that the token exists. To prevent potential issues (like emitting updates for non-existent tokens), it's advisable to add a token existence check before proceeding with the event emission. For instance, you could consider:

         #[external(v0)]
         fn update_token_metadata(ref self: ContractState, token_id: u256) {
             // Only owner can update metadata
             self.ownable.assert_only_owner();
+
+            // Verify that the token exists; handle non-existent tokens gracefully
+            if (!self.erc721._exists(token_id)) {
+                // Optionally: raise an error or return early
+                return;
+            }
 
             // Emit metadata update event
             self.erc4906.emit_metadata_update(token_id);
         }

Please consider adding this token existence validation to strengthen the update process.

Comment on lines +105 to +112
#[external(v0)]
fn update_token_metadata(ref self: ContractState, token_id: u256) {
// Only owner can update metadata
self.ownable.assert_only_owner();

// Emit metadata update event
self.erc4906.emit_metadata_update(token_id);
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Verify token existence for ERC1155, sensei!

Similar to ERC721, consider adding token existence verification. For ERC1155, you might want to check if the token has ever been minted.


🏁 Script executed:

#!/bin/bash
# Search for token existence checks in ERC1155 implementations
ast-grep --pattern 'fn $FUNC($_, token_id: u256) {
  $$$
  self.erc1155.total_supply(token_id)
  $$$
}'

Length of output: 105


Ohayo, sensei! Attention to ERC1155 token metadata update logic needed.

It appears that the current implementation in
examples/spawn-and-move/src/externals/erc1155.cairo (lines 105-112) does not verify that the token has been minted (or exists) before updating its metadata. Unlike the ERC721 approach where token existence is checked, this ERC1155 function lacks a guard to ensure that metadata updates are performed only on tokens with a positive supply.

Actionable suggestions:

  • Insert token existence verification: Before calling self.erc4906.emit_metadata_update(token_id), add a check to confirm that the token has been minted. For example:
    let supply = self.erc1155.total_supply(token_id);
    // Only proceed if token exists (supply > 0)
    assert supply > 0, 'Token does not exist';
  • Review similar patterns in ERC721 implementations: Ensure consistency and possibly reuse proven logic from the ERC721 token methods.

Please verify and implement these changes accordingly.

@Larkooo Larkooo enabled auto-merge (squash) February 18, 2025 09:32
@Larkooo Larkooo merged commit e5b93ac into dojoengine:main Feb 18, 2025
13 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.

2 participants