Skip to content

Conversation

@typicalHuman
Copy link
Contributor

@typicalHuman typicalHuman commented Oct 24, 2025

Use namespaced storage for variables when upgradeability is enabled:

  • For ERC-20, use namespaced storage for tokenBridge when cross-chain bridging is set to 'custom' and upgradeability is enabled.
  • For ERC-721, use namespaced storage for _nextTokenId when mintable, auto increment IDs, and upgradeability are enabled.

#383

…ity, using _nextTokenId in namespaced storage for safe upgradeable minting.
@typicalHuman typicalHuman requested review from a team as code owners October 24, 2025 12:46
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 24, 2025

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.

Walkthrough

The PR adds struct support to the Solidity contract builder and introduces UUPS-upgradeable ERC721 minting with auto-incremented token IDs using namespaced storage slots. New utility functions generate storage slot hashes via keccak-256, and test cases verify the incremental minting pattern alongside existing deployments.

Changes

Cohort / File(s) Summary
Changeset and Dependencies
.changeset/rude-nails-mate.md, packages/core/solidity/package.json
Bumped @openzeppelin/wizard to minor version and added keccak v3.0.4 dependency for hash generation.
Struct Support Infrastructure
packages/core/solidity/src/contract.ts, packages/core/solidity/src/print.ts
Introduced ContractStruct interface with name, comments, and variables; added structs collection to Contract; extended ContractBuilder with struct management methods and accessor.
Storage Slot Generation Utilities
packages/core/solidity/src/utils/namespaced-storage-generator.ts, packages/core/solidity/src/utils/namespaced-storage-generator.test.ts
Implemented namespaced storage slot generation via dual keccak-256 hashing with BigInt masking; added test cases validating three input/output pairs.
ERC721 Incremental Minting
packages/core/solidity/src/erc721.ts, packages/core/solidity/src/erc721.test.ts, packages/core/solidity/src/erc721.test.ts.md
Extended addMintable to accept UUPS flag; UUPS path creates storage struct and uses namespaced storage slot for \_nextTokenId tracking; added test case and documentation for full upgradeable UUPS + managed + incremental variant.

Sequence Diagram

sequenceDiagram
    participant BuildERC721 as buildERC721()
    participant AddMintable as addMintable()
    participant StorageGen as Storage Utilities
    participant Contract as Contract Builder
    
    BuildERC721->>AddMintable: addMintable(..., uups: true)
    
    alt UUPS Path (upgradeable)
        AddMintable->>StorageGen: getStorageStruct('Storage')
        StorageGen-->>AddMintable: ContractStruct with _nextTokenId
        AddMintable->>Contract: addStructVariable(Storage, ...)
        Contract->>Contract: structMap.set('Storage', struct)
        
        AddMintable->>StorageGen: generateNamespacesStorageSlot(namespacedName)
        StorageGen->>StorageGen: keccak(keccak(input)) + masking
        StorageGen-->>AddMintable: storage slot (0x...)
        
        AddMintable->>AddMintable: Create _getStorage() function
        AddMintable->>AddMintable: Add assembly code<br/>to set storage slot
        AddMintable->>Contract: addFunction(_getStorage)
        AddMintable->>Contract: addFunction(safeMint with<br/>_nextTokenId tracking)
    else Non-UUPS Path
        AddMintable->>Contract: Use standard minting logic
    end
    
    AddMintable-->>BuildERC721: Complete
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

The changes introduce struct support infrastructure alongside UUPS-aware ERC721 minting with novel storage slot generation logic. While individual pieces are relatively straightforward, the integration across multiple files and introduction of cryptographic operations (dual keccak-256 hashing with BigInt masking) requires careful validation of correctness and interaction points between the contract builder, storage utilities, and ERC721 implementation.

Possibly related PRs

Suggested reviewers

  • ericglau
  • ernestognw
  • gonzaotc

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% 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
Title Check ✅ Passed The title "Use namespaced storage for variables when upgradeable" is clearly related to the actual changeset. The PR introduces a new namespaced storage generation utility (namespaced-storage-generator.ts) and integrates it into the ERC721 builder to support upgradeability with auto-incrementing token IDs by storing the _nextTokenId in namespaced storage. While the title focuses on the implementation mechanism (namespaced storage for variables) rather than the broader user-facing feature (ERC721 auto-incrementing IDs), it accurately describes a significant and core aspect of what is being changed. A developer scanning the PR history would understand that this change introduces a technique for safely managing storage in upgradeable contracts, which is the primary technical contribution of this PR.
Description Check ✅ Passed The pull request description relates directly to the changeset provided. The description outlines support for ERC721 minting with auto-incrementing IDs using namespaced storage when upgradeability is enabled, and the raw_summary confirms this is exactly what the PR implements: new ERC721 functionality with _nextTokenId stored in namespaced storage for UUPS upgradeable contracts. The description accurately describes the core changes including the struct support, the namespaced storage generator utilities, and the test cases added. While the description also mentions ERC-20 changes, the PR objectives clarify this is specifically an ERC721-focused PR (issue #383 references ERC721), and the changes are clearly related to the stated objectives.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link
Contributor

github-actions bot commented Oct 24, 2025

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@socket-security
Copy link

socket-security bot commented Oct 24, 2025

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

Ignoring alerts on:

View full report

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: 3

🧹 Nitpick comments (4)
packages/core/solidity/src/utils/namespaced-storage-generator.ts (1)

3-5: Consider making the namespace prefix configurable.

The getNamespacedStorageName function hardcodes "myProject" as the namespace prefix. While this works for the current use case, consider making it configurable to support different project naming conventions.

Example refactor:

-export function getNamespacedStorageName(name: string) {
-  return `myProject.${name}`;
+export function getNamespacedStorageName(name: string, namespace: string = 'myProject') {
+  return `${namespace}.${name}`;
 }
packages/core/solidity/src/erc721.ts (3)

103-103: Use strict equality for the UUPS check.

Avoid implicit coercion here; use === for clarity and type safety.

-    addMintable(c, access, allOpts.incremental, allOpts.uriStorage, allOpts.upgradeable == 'uups');
+    addMintable(c, access, allOpts.incremental, allOpts.uriStorage, allOpts.upgradeable === 'uups');

178-209: UUPS+incremental flow looks good overall; minor nits.

  • The $ identifier is allowed in Solidity but is unconventional; keep if you prefer collision‑resistance in generated code.
  • Returning uint256 on incremental path and adding _setTokenURI when uriStorage is on are correct.

282-294: Adopt unique struct names for forward-compatible ERC-7201 adoption.

Currently, only ERC721 with UUPS generates struct Storage (line 190); no collision exists. However, if ERC20 or ERC1155 later adopt ERC-7201, they will generate conflicting struct Storage definitions. Consider refactoring now to use unique names (e.g., ${ContractName}Storage) to prevent future conflicts and improve code clarity.

Minimal changes:

  • Update getStorageFunction(structName: string) to template the return type
  • Update getStorageStruct(name: string) to use ${name}Storage (already uses c.name, so only the struct field name needs adjustment to ${name}Storage)
  • Update line 187–198 call sites in addMintable to pass storageStruct.name and reference it in code generation
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d34a00 and 9842397.

⛔ Files ignored due to path filters (1)
  • packages/core/solidity/src/erc721.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (9)
  • .changeset/rude-nails-mate.md (1 hunks)
  • packages/core/solidity/package.json (1 hunks)
  • packages/core/solidity/src/contract.ts (6 hunks)
  • packages/core/solidity/src/erc721.test.ts (1 hunks)
  • packages/core/solidity/src/erc721.test.ts.md (1 hunks)
  • packages/core/solidity/src/erc721.ts (5 hunks)
  • packages/core/solidity/src/print.ts (4 hunks)
  • packages/core/solidity/src/utils/namespaced-storage-generator.test.ts (1 hunks)
  • packages/core/solidity/src/utils/namespaced-storage-generator.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-15T22:49:25.653Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#609
File: .changeset/sour-hats-grow.md:2-6
Timestamp: 2025-08-15T22:49:25.653Z
Learning: In OpenZeppelin contracts-wizard, breaking changes that have concrete migration paths (like dependency migrations from Community Contracts to OpenZeppelin Contracts) can be handled as minor version bumps instead of major bumps, per maintainer ernestognw's versioning policy.

Applied to files:

  • .changeset/rude-nails-mate.md
🧬 Code graph analysis (3)
packages/core/solidity/src/print.ts (1)
packages/core/solidity/src/contract.ts (2)
  • structs (124-126)
  • ContractStruct (56-60)
packages/core/solidity/src/utils/namespaced-storage-generator.test.ts (1)
packages/core/solidity/src/utils/namespaced-storage-generator.ts (1)
  • generateNamespacesStorageSlot (7-19)
packages/core/solidity/src/erc721.ts (2)
packages/core/solidity/src/contract.ts (3)
  • ContractBuilder (82-257)
  • BaseFunction (39-45)
  • ContractStruct (56-60)
packages/core/solidity/src/utils/namespaced-storage-generator.ts (2)
  • generateNamespacesStorageSlot (7-19)
  • getNamespacedStorageName (3-5)
🪛 Gitleaks (8.28.0)
packages/core/solidity/src/erc721.test.ts.md

[high] 805-805: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ 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). (2)
  • GitHub Check: Socket Security: Pull Request Alerts
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (14)
.changeset/rude-nails-mate.md (1)

1-5: LGTM!

The changeset appropriately documents the new feature as a minor version bump, which aligns with the versioning policy for new functionality.

packages/core/solidity/src/print.ts (2)

9-9: LGTM!

The ContractStruct import addition enables struct printing support.


262-274: LGTM!

The printStruct function follows the same pattern as printFunction2 and properly handles both empty and non-empty structs with appropriate bracing.

packages/core/solidity/src/erc721.test.ts.md (2)

805-805: Dismiss static analysis false positive.

The Gitleaks tool flagged line 805 as a potential API key, but this is a false positive. MYTOKEN_STORAGE_LOCATION is a deterministic storage slot constant computed via the ERC-7201 namespaced storage pattern (keccak256-based), not a secret or API key.


800-840: LGTM! ERC-7201 namespaced storage pattern correctly implemented.

The generated contract properly implements:

  • Storage struct with @custom:storage-location annotation
  • Deterministic storage slot constant
  • Internal _getStorage function using inline assembly
  • Auto-incrementing tokenId in safeMint

This follows the ERC-7201 namespaced storage pattern for upgrade-safe state management.

packages/core/solidity/src/utils/namespaced-storage-generator.ts (2)

7-19: LGTM! ERC-7201 implementation looks correct.

The storage slot generation implements the ERC-7201 pattern:

  1. Hash the namespace string with keccak256
  2. Subtract 1 to get innerNum
  3. Encode to 32 bytes
  4. Hash again with keccak256
  5. Mask the lowest byte

This provides collision-resistant namespaced storage slots for upgradeable contracts.


21-26: LGTM! Good overflow protection.

The padTo32Bytes helper correctly validates that values fit within uint256 (64 hex characters = 32 bytes) before encoding.

packages/core/solidity/src/contract.ts (5)

56-60: LGTM! Clean struct interface.

The ContractStruct interface follows the same pattern as other contract elements with name, comments, and content (variables in this case).


96-96: LGTM!

The structMap follows the established pattern of using Maps for contract elements (parentMap, functionMap).


124-126: LGTM!

The structs getter provides a clean public API for accessing structs, consistent with existing getters.


187-198: LGTM!

The addStruct method follows the same deduplication pattern as addFunction, preventing duplicate struct definitions.


248-256: LGTM! Safe struct variable management.

The addStructVariable method properly handles both creating new structs and adding variables to existing ones, with duplicate detection to prevent redundant additions.

packages/core/solidity/src/utils/namespaced-storage-generator.test.ts (1)

4-23: ERC-7201 compliance verified. The implementation correctly follows the specification: it computes keccak256(keccak256(id) - 1) & ~0xff, with the intermediate value properly encoded to 32 bytes (matching abi.encode(uint256(...))). The test cases are well-structured with appropriate input variations.

packages/core/solidity/src/erc721.ts (1)

1-1: LGTM on imports.

Imports look correct and scoped. No issues.

Also applies to: 15-15

Copy link
Member

@ericglau ericglau left a comment

Choose a reason for hiding this comment

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

Thank you for the PR! This looks like the right approach.

I changed the keccak library to use ethereum-cryptography instead, as that is more recent and is maintained under the ethereum GitHub org.

Left some additional comments about how the namespace-related code is generated. Let us know if you'd like to take those on, otherwise we can pick up any remaining items. Thanks!

@typicalHuman typicalHuman requested a review from ericglau October 27, 2025 13:03
@ericglau
Copy link
Member

ericglau commented Oct 27, 2025

Thanks @typicalHuman. Would you mind signing the CLA according to #704 (comment)?

We'll plan to update the UI to allow adding a namespace prefix.

@typicalHuman
Copy link
Contributor Author

I confirm that I have read and hereby agree to the OpenZeppelin Contributor License Agreement

@ericglau ericglau changed the title Support for ERC721 with Mintable → Auto Increment IDs and Upgradeabil… Use namespaced storage for variables when upgradeable Oct 27, 2025
Copy link
Member

@ericglau ericglau left a comment

Choose a reason for hiding this comment

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

We'll do another review internally before proceeding, but this LGTM, thanks!

@ericglau
Copy link
Member

@SocketSecurity ignore-all
Looks like AI-detected false positives

Copy link
Member

@ernestognw ernestognw left a comment

Choose a reason for hiding this comment

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

Minor nits. LGTM

@ericglau ericglau merged commit 38da80c into OpenZeppelin:master Oct 29, 2025
19 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Oct 29, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants