Skip to content

ERC721URIStorage component#1639

Merged
immrsd merged 10 commits intomainfrom
feat/erc721-uri-storage
Jan 28, 2026
Merged

ERC721URIStorage component#1639
immrsd merged 10 commits intomainfrom
feat/erc721-uri-storage

Conversation

@immrsd
Copy link
Copy Markdown
Collaborator

@immrsd immrsd commented Jan 26, 2026

Fixes #1580

Summary by CodeRabbit

Release Notes

  • New Features

    • ERC721URIStorage component now available for per-token URI storage in ERC721 tokens
    • ERC721 token URI trait with default implementation for token URI handling
    • MetadataUpdate and BatchMetadataUpdate events for URI change tracking
  • Tests

    • Added comprehensive test suite for ERC721URIStorage functionality covering token URI operations, burn cleanup, transfers, and metadata event emissions
    • Extended ERC721 test mocks with URI storage integration
  • Chores

    • Updated build configuration to include new test mocks

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

@immrsd immrsd self-assigned this Jan 26, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 26, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review

Walkthrough

This PR implements the ERC721URIStorage extension, adding per-token URI storage capabilities to ERC721 tokens. Changes include a new ERC721URIStorageComponent with storage mappings and events, a new trait-based token_uri abstraction with default implementations, updates to the macro system to recognize the component, test mocks, and a comprehensive test suite.

Changes

Cohort / File(s) Summary
Macro System Updates
packages/macros/src/attribute/with_components/components.rs, diagnostics.rs, parser.rs
Added ERC721URIStorage variant to AllowedComponents enum; extended from_str and get_info methods; added ERC721_URI_STORAGE_HOOKS_MISSING diagnostic warning; enhanced parser to detect hooks and validate component-specific requirements for URI storage.
ERC721 Core Implementation
packages/token/src/erc721/erc721.cairo
Introduced ERC721TokenURITrait and ERC721TokenURIDefaultImpl providing token_uri method; refactored token_uri logic to delegate through trait instead of inline implementation; updated embeddable impls to include new trait bounds.
ERC721URIStorage Extension
packages/token/src/erc721/extensions/erc721_uri_storage.cairo
New component module with Storage (per-token URI map), MetadataUpdate and BatchMetadataUpdate events, ERC721TokenURIStorageImpl (resolves stored or computed URI), and InternalImpl (set_token_uri with validation, after_update hook for burn cleanup).
Public Exports & Re-exports
packages/token/src/erc721.cairo, packages/token/src/erc721/extensions.cairo, packages/presets/src/erc721.cairo
Added ERC721TokenURIDefaultImpl to public use statements; added erc721_uri_storage module and ERC721URIStorageComponent export; removed DefaultConfig from erc721_consecutive export.
Test Mocks
packages/test_common/src/mocks/erc721.cairo, votes.cairo
Added ERC721URIStorageMockABI trait and ERC721URIStorageMock contract with mint, burn, set_token_uri methods; integrated ERC721TokenURIDefaultImpl imports across multiple mock variants (DualCase, Snake, SnakeWithHooks, Enumerable, Mintable, Wrapper, Consecutive).
Test Suite
packages/token/src/tests/erc721.cairo, erc721/test_erc721_uri_storage.cairo
Added test_erc721_uri_storage module reference; introduced 251 lines of comprehensive tests covering token_uri resolution, MetadataUpdate event emission, burn cleanup, transfer preservation, and integration scenarios.
Configuration & Refactoring
packages/token/Scarb.toml, packages/token/src/erc20/extensions/erc4626/erc4626.cairo
Added ERC721URIStorageMock to build-external-contracts; simplified ERC4626 withdraw fee handling match pattern (no behavior change).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • bidzyyys
  • ericnordelo

Poem

🐰 A storage for URIs, per token so fine,
New traits and components, all in design,
The hooks catch the burns, clean up with care,
Default impls provided, URI logic fair! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR contains one minor out-of-scope change: simplification of ERC4626 fee handling match pattern unrelated to ERC721URIStorage. Remove the ERC4626 fee handling simplification (packages/token/src/erc20/extensions/erc4626/erc4626.cairo) as it is outside the scope of the ERC721URIStorage feature.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically identifies the primary change: adding an ERC721URIStorage component to the codebase.
Linked Issues check ✅ Passed The PR successfully implements the ERC721URIStorage extension per issue #1580, including component implementation, trait definitions, test coverage, and macro integration.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/erc721-uri-storage

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 26, 2026

🧪 Cairo Contract Size Benchmark Diff

BYTECODE SIZE (felts) (limit: 81,920 felts)

Contract Old New Δ Note
ERC721BlockNumberVotesMock 17755 17889 🟢 +134
ERC721TimestampVotesMock 17755 17889 🟢 +134
ERC721URIStorageMock 12720 +12720 ✅ NEW
SnakeERC721MockWithHooks 9761 9895 🟢 +134

SIERRA CONTRACT CLASS SIZE (bytes) (limit: 4,089,446 bytes)

Contract Old New Δ Note
ERC4626AssetsFeesMock 433390 433246 🔴 −144
ERC4626ExternalVaultMock 297595 297482 🔴 −113
ERC4626LimitsMock 299298 299149 🔴 −149
ERC4626Mock 284571 284443 🔴 −128
ERC4626MockWithHooks 284882 284737 🔴 −145
ERC4626OffsetMock 297211 297172 🔴 −39
ERC4626SharesFeesMock 398466 398351 🔴 −115
ERC721BlockNumberVotesMock 379112 380897 🟢 +1785
ERC721TimestampVotesMock 379082 380855 🟢 +1773
ERC721URIStorageMock 275404 +275404 ✅ NEW
SnakeERC721MockWithHooks 216423 218393 🟢 +1970

This comment was generated automatically from benchmark diffs.

Copy link
Copy Markdown
Collaborator Author

@immrsd immrsd left a comment

Choose a reason for hiding this comment

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

We should decide if the ERC721URIComponent should implement SRC5 and register an interface ID.

In the Solidity implementation it returns true for ERC4906_INTERFACE_ID, but there's actually no external functions to generate SRC5 id upon:

// Interface ID as defined in ERC-4906. This does not correspond to a traditional interface ID as ERC-4906 only
// defines events and does not include any external function.
bytes4 private constant ERC4906_INTERFACE_ID = bytes4(0x49064906);

We can:

  1. register the same ID (0x49064906) to support off-chain integrations
  2. avoid registering any interface IDs
  3. compute a different ID following SRC5 and register it in the initializer

Comment thread packages/token/src/erc721/extensions.cairo Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@packages/macros/src/attribute/with_components/parser.rs`:
- Around line 364-372: The block handling AllowedComponents::ERC721URIStorage is
misformatted; run rustfmt (cargo fmt --all) to normalize spacing and alignment
around the hook_called declaration and the
Diagnostic::warn/warnings::ERC721_URI_STORAGE_HOOKS_MISSING push, ensuring the
code for AllowedComponents::ERC721URIStorage, hook_called, Diagnostic::warn, and
warnings.push follows project formatting conventions.
- Around line 213-221: The current check finds imports of ImmutableConfig via
immutable_config_import_re and sets immutable_config_imported, but
imported_immutable_config_implemented only checks code.contains("of
ImmutableConfig") so imports using an alias (e.g., `ImmutableConfig as Alias`)
are missed; update the logic to capture any alias name from the regex match
created in immutable_config_import_re (or add a second regex to capture `as
<Alias>`), then check for either `of ImmutableConfig` or `of <Alias>` (i.e., set
imported_immutable_config_implemented = code.contains("of ImmutableConfig") ||
code.contains(&format!("of {}", alias))). After making the change, run cargo fmt
to fix the CI formatting diffs.

In `@packages/token/src/erc721/extensions.cairo`:
- Around line 4-8: The extensions module is missing a re-export of DefaultConfig
from erc721_consecutive, breaking API consistency; update the extensions.cairo
module to publicly re-export DefaultConfig by adding a pub use for
erc721_consecutive::DefaultConfig alongside the existing
ERC721ConsecutiveComponent and ERC721URIStorageComponent exports so consumers
can import DefaultConfig from extensions.cairo rather than the submodule.

Comment thread packages/macros/src/attribute/with_components/parser.rs Outdated
Comment thread packages/macros/src/attribute/with_components/parser.rs Outdated
Comment thread packages/token/src/erc721/extensions.cairo
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 26, 2026

Codecov Report

❌ Patch coverage is 92.59259% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.15%. Comparing base (924e9d0) to head (7490334).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...s/token/src/erc20/extensions/erc4626/erc4626.cairo 50.00% 1 Missing ⚠️
...ken/src/erc721/extensions/erc721_uri_storage.cairo 94.73% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1639      +/-   ##
==========================================
+ Coverage   94.11%   94.15%   +0.04%     
==========================================
  Files          94       95       +1     
  Lines        2360     2380      +20     
==========================================
+ Hits         2221     2241      +20     
  Misses        139      139              
Files with missing lines Coverage Δ
packages/presets/src/erc721.cairo 91.30% <ø> (ø)
packages/token/src/erc721/erc721.cairo 93.89% <100.00%> (+0.81%) ⬆️
...s/token/src/erc20/extensions/erc4626/erc4626.cairo 81.45% <50.00%> (-0.15%) ⬇️
...ken/src/erc721/extensions/erc721_uri_storage.cairo 94.73% <94.73%> (ø)

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 924e9d0...7490334. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Collaborator

@bidzyyys bidzyyys left a comment

Choose a reason for hiding this comment

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

Great job @immrsd!

Comment thread packages/macros/src/attribute/with_components/parser.rs
Copy link
Copy Markdown
Member

@ericnordelo ericnordelo left a comment

Choose a reason for hiding this comment

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

Looking great @immrsd. Left two small comments

Comment thread packages/token/src/erc721/erc721.cairo
Comment thread packages/token/src/erc721/extensions.cairo Outdated
Copy link
Copy Markdown
Member

@ericnordelo ericnordelo left a comment

Choose a reason for hiding this comment

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

LGTM!

@immrsd immrsd merged commit d4b82bb into main Jan 28, 2026
13 checks passed
@ericnordelo ericnordelo deleted the feat/erc721-uri-storage branch January 28, 2026 09:50
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.

[Feature]: Add ERC-721 UriStorage Extension

3 participants