Skip to content

Add cross-chain options for ERC721, ERC1155, and Governor (Contracts 5.7) - #825

Merged
ericglau merged 20 commits into
OpenZeppelin:masterfrom
ericglau:57bridgeable
Jul 31, 2026
Merged

Add cross-chain options for ERC721, ERC1155, and Governor (Contracts 5.7)#825
ericglau merged 20 commits into
OpenZeppelin:masterfrom
ericglau:57bridgeable

Conversation

@ericglau

@ericglau ericglau commented Jul 17, 2026

Copy link
Copy Markdown
Member

Adds Wizard support for the new cross-chain contracts in OpenZeppelin Contracts 5.7.

New options

  • ERC721 / ERC1155: crossChainBridging (ERC-7786 Native) embeds a bridge directly in the token via ERC721Crosschain/ERC1155Crosschain — outbound transfers burn, inbound transfers mint. Adds a CrosschainLinked.Link[] constructor argument and an access-controlled setLink function, with the crossChainLinkAllowOverride sub-option. Mirrors the existing ERC20 erc7786native option.
  • Governor: crossChainExecution adds the GovernorCrosschain extension, letting passed proposals relay execution to other chains through ERC-7786 gateways. The CrosschainRemoteExecutor on target chains is deployed by the user (not generated); gateway and executor are per-proposal arguments to relayCrosschain.

Combining ERC721 auto-increment IDs with bridging is allowed but shows a warning (IDs increment independently per chain; mint on a single chain and link non-minting counterparts to avoid collisions that strand bridged tokens).

Covers core codegen, UI, AI assistant descriptions/schemas/function definitions, MCP tools, and CLI.

Fixes

Upgradeable crossChainBridging combinations were previously excluded from the exhaustive compile matrix; they are now covered via reduced blueprints, which surfaced two existing compile errors in upgradeable ERC20 bridging variants (fixed here):

  • erc7786native referenced the untranspiled CrosschainLinked.Link[] in the initializer.
  • custom with managed access transpiled the AuthorityUtils library import to a nonexistent file.

Two fixes outside the cross-chain surface:

  • Account: the IERC4337 import path dropped its draft- prefix in Contracts 5.7, so generated account contracts import interfaces/IERC4337.sol.
  • UI: the clickable import links resolved @openzeppelin/contracts from a hoisted copy in node_modules and pointed at v5.4.0; they now use the version the Wizard's output is generated against. Affects all Solidity tabs.

Additionally, downloaded Foundry and Hardhat projects now compile when constructors have non-address arguments (e.g. cross-chain links, or Governor's token and timelock): the generated test and script files declare typed placeholders and comment out the deployment with a TODO, instead of calling the constructor with missing arguments.

Before merging

  • Contracts 5.7.0 final released
  • Re-pin @openzeppelin/contracts and @openzeppelin/contracts-upgradeable to ^5.7.0 (core devDependencies and both Hardhat environments) and regenerate lockfiles/snapshot via prepare and update-env
  • Update compatibleContractsSemver to ^5.7.0
  • Confirm API docs anchors for ERC721Crosschain, ERC1155Crosschain, and GovernorCrosschain resolve — the anchors are not published yet; they land with [CI] Update API docs for OpenZeppelin/openzeppelin-contracts v5.7.0 docs#226. The help links already use the correct URLs and currently resolve to the right page without scrolling to the anchor.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a204d973-718b-4d0d-b7eb-702ce29690a5

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds ERC721/ERC1155 ERC-7786 bridging and Governor cross-chain execution options, wires them through Solidity builders, generators, MCP, AI, CLI, and UI surfaces, updates deployment templates, and upgrades generated compatibility metadata to OpenZeppelin Contracts 5.7.0.

Changes

Solidity cross-chain generation

Layer / File(s) Summary
Cross-chain option contracts and builders
packages/core/solidity/src/{erc721,erc1155,governor}.ts, packages/core/solidity/src/generate/*
Adds cross-chain option types, defaults, access-control requirements, extension wiring, and constrained option-generation matrices.
Option surfaces and tool wiring
packages/common/src/ai/*, packages/mcp/src/solidity/tools/*, packages/ui/src/solidity/*, packages/cli/src/cli.test.ts.md
Exposes ERC721/ERC1155 bridging and Governor execution through schemas, tool handlers, help output, AI definitions, and controls.
Deployment template generation
packages/core/solidity/src/zip-{foundry,hardhat}.ts
Generates typed constructor variables and comments deployment/assertion code when non-address arguments require manual values.
Compatibility updates and generated coverage
packages/core/solidity/**/*.md, packages/core/confidential/**, packages/core/uniswap-hooks/**, packages/core/solidity/package.json
Updates Contracts compatibility and remappings to 5.7.0 and adds cross-chain builder, snapshot, ZIP, and integration coverage.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SolidityUI
  participant MCPTool
  participant ContractBuilder
  participant GeneratedOutput
  User->>SolidityUI: select cross-chain option
  SolidityUI->>MCPTool: submit option values
  MCPTool->>ContractBuilder: pass ERC or Governor options
  ContractBuilder->>GeneratedOutput: add cross-chain extension and deployment wiring
  GeneratedOutput-->>User: return Solidity project output
Loading

Suggested reviewers: pasevin, arr00

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main cross-chain options added for ERC721, ERC1155, and Governor in Contracts 5.7.
Description check ✅ Passed The description directly explains the cross-chain features, supporting changes, fixes, and Contracts 5.7 updates in the changeset.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@socket-security

socket-security Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​@​openzeppelin/​contracts@​5.6.1 ⏵ 5.7.010010010093 +4100
Updatednpm/​@​openzeppelin/​contracts-upgradeable@​5.6.0 ⏵ 5.7.0100 +1100100 +196 +1100

View full report

@socket-security

socket-security Bot commented Jul 17, 2026

Copy link
Copy Markdown

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.

View full report

@ericglau
ericglau marked this pull request as ready for review July 30, 2026 14:06
@ericglau
ericglau requested review from a team as code owners July 30, 2026 14:06

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/solidity/src/zip-foundry.ts (1)

194-230: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Comment out run() when initialOwner is required
args.length misses the transparent-proxy initialOwner placeholder. For contracts with no constructor args, this emits an uncommented run() containing address initialOwner = <Set initialOwner address here>;, which makes the generated script invalid. Include needsInitialOwnerVariable(c, opts) in the guard.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/solidity/src/zip-foundry.ts` around lines 194 - 230, The
getScript function currently only comments out run() when constructor arguments
exist, missing the initialOwner placeholder for transparent proxies. Update the
run() guard to also account for needsInitialOwnerVariable(c, opts), while
preserving the existing addTodoAndCommentOut behavior and deployment flow.
🧹 Nitpick comments (1)
packages/core/solidity/src/generate/erc1155.ts (1)

18-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

crossChainLinkAllowOverride never generates the true branch.

Both blueprint and crossChainBridgingUpgradeableBlueprint fix crossChainLinkAllowOverride: [false], so the generated compile-coverage matrix never exercises _setLink(gateway, counterpart, true) from addERC1155Crosschain in erc1155.ts. Consider covering both values for at least the non-upgradeable variants.

♻️ Proposed fix
-  crossChainLinkAllowOverride: [false],
+  crossChainLinkAllowOverride: booleans,

Also applies to: 25-47

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/solidity/src/generate/erc1155.ts` around lines 18 - 24, Update
the ERC1155 compile-coverage option definitions in blueprint and
crossChainBridgingUpgradeableBlueprint so crossChainLinkAllowOverride covers
both false and true, ensuring non-upgradeable variants exercise the
_setLink(..., true) branch while preserving existing upgradeable coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/solidity/src/zip-hardhat.test.ts.md`:
- Around line 625-633: The generated Ignition module templates use undeclared
constructor arguments, so deployment code cannot be evaluated or type-checked.
In packages/core/solidity/src/zip-hardhat.test.ts.md lines 625-633, update the
MyToken deployment call to use typed placeholder values or comment out the call
until links and initialOwner are supplied; apply the same treatment in lines
789-797 for _token and _timelock, preserving the surrounding module structure.

In `@packages/ui/src/solidity/GovernorControls.svelte`:
- Line 263: Update the helpLink value in GovernorControls to reference a
currently published OpenZeppelin governance documentation anchor; if no valid
anchor exists, remove the link rather than retaining the dead
`#GovernorCrosschain` fragment.

---

Outside diff comments:
In `@packages/core/solidity/src/zip-foundry.ts`:
- Around line 194-230: The getScript function currently only comments out run()
when constructor arguments exist, missing the initialOwner placeholder for
transparent proxies. Update the run() guard to also account for
needsInitialOwnerVariable(c, opts), while preserving the existing
addTodoAndCommentOut behavior and deployment flow.

---

Nitpick comments:
In `@packages/core/solidity/src/generate/erc1155.ts`:
- Around line 18-24: Update the ERC1155 compile-coverage option definitions in
blueprint and crossChainBridgingUpgradeableBlueprint so
crossChainLinkAllowOverride covers both false and true, ensuring non-upgradeable
variants exercise the _setLink(..., true) branch while preserving existing
upgradeable coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ac2fa320-9c7b-4b4c-a183-2570d4bb5ac3

📥 Commits

Reviewing files that changed from the base of the PR and between 90100ee and 8e01a9a.

⛔ Files ignored due to path filters (20)
  • packages/cli/src/cli.test.ts.snap is excluded by !**/*.snap
  • packages/core/confidential/src/erc7984.test.ts.snap is excluded by !**/*.snap
  • packages/core/confidential/src/get-versioned-remappings.test.ts.snap is excluded by !**/*.snap
  • packages/core/confidential/src/zip-hardhat.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/account.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/custom.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/environments/hardhat/package-lock.json is excluded by !**/package-lock.json
  • packages/core/solidity/src/environments/hardhat/upgradeable/package-lock.json is excluded by !**/package-lock.json
  • packages/core/solidity/src/erc1155.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/erc20.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/erc721.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/get-versioned-remappings.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/governor.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/stablecoin.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/zip-foundry.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/zip-hardhat-polkadot.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/zip-hardhat.test.ts.snap is excluded by !**/*.snap
  • packages/core/uniswap-hooks/src/get-versioned-remappings.test.ts.snap is excluded by !**/*.snap
  • packages/core/uniswap-hooks/src/hooks.test.ts.snap is excluded by !**/*.snap
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (52)
  • .changeset/solidity-57-crosschain.md
  • packages/cli/src/cli.test.ts.md
  • packages/common/src/ai/descriptions/solidity.ts
  • packages/common/src/ai/schemas/solidity.ts
  • packages/core/confidential/src/erc7984.test.ts.md
  • packages/core/confidential/src/get-versioned-remappings.test.ts.md
  • packages/core/confidential/src/zip-hardhat.test.ts.md
  • packages/core/solidity/package.json
  • packages/core/solidity/src/account.test.ts.md
  • packages/core/solidity/src/account.ts
  • packages/core/solidity/src/custom.test.ts.md
  • packages/core/solidity/src/environments/hardhat/package.json
  • packages/core/solidity/src/environments/hardhat/upgradeable/package.json
  • packages/core/solidity/src/erc1155.test.ts
  • packages/core/solidity/src/erc1155.test.ts.md
  • packages/core/solidity/src/erc1155.ts
  • packages/core/solidity/src/erc20.test.ts.md
  • packages/core/solidity/src/erc20.ts
  • packages/core/solidity/src/erc721.test.ts
  • packages/core/solidity/src/erc721.test.ts.md
  • packages/core/solidity/src/erc721.ts
  • packages/core/solidity/src/generate/erc1155.ts
  • packages/core/solidity/src/generate/erc20.ts
  • packages/core/solidity/src/generate/erc721.ts
  • packages/core/solidity/src/generate/governor.ts
  • packages/core/solidity/src/get-versioned-remappings.test.ts.md
  • packages/core/solidity/src/governor.test.ts
  • packages/core/solidity/src/governor.test.ts.md
  • packages/core/solidity/src/governor.ts
  • packages/core/solidity/src/stablecoin.test.ts.md
  • packages/core/solidity/src/utils/version.ts
  • packages/core/solidity/src/zip-foundry.test.ts
  • packages/core/solidity/src/zip-foundry.test.ts.md
  • packages/core/solidity/src/zip-foundry.ts
  • packages/core/solidity/src/zip-hardhat-polkadot.test.ts.md
  • packages/core/solidity/src/zip-hardhat.test.ts
  • packages/core/solidity/src/zip-hardhat.test.ts.md
  • packages/core/solidity/src/zip-hardhat.ts
  • packages/core/uniswap-hooks/src/get-versioned-remappings.test.ts.md
  • packages/core/uniswap-hooks/src/hooks.test.ts.md
  • packages/mcp/src/solidity/tools/erc1155.test.ts
  • packages/mcp/src/solidity/tools/erc1155.ts
  • packages/mcp/src/solidity/tools/erc721.test.ts
  • packages/mcp/src/solidity/tools/erc721.ts
  • packages/mcp/src/solidity/tools/governor.test.ts
  • packages/mcp/src/solidity/tools/governor.ts
  • packages/ui/api/ai-assistant/function-definitions/solidity.ts
  • packages/ui/src/solidity/ERC1155Controls.svelte
  • packages/ui/src/solidity/ERC721Controls.svelte
  • packages/ui/src/solidity/GovernorControls.svelte
  • packages/ui/src/solidity/crosschain-incremental-tooltip.ts
  • packages/ui/src/solidity/inject-hyperlinks.ts

Comment thread packages/core/solidity/src/zip-hardhat.test.ts.md
Comment thread packages/ui/src/solidity/GovernorControls.svelte
ericglau and others added 6 commits July 30, 2026 10:33
Cleanups over the cross-chain bridging change, with no change to generated
output:

- Extract the shared `CrosschainLinked` wiring and the `setLink` function
  definition into `set-crosschain-linked.ts`. ERC20, ERC721 and ERC1155 had
  three byte-identical copies differing only in the parent extension.
- Drop the single-case `switch` dispatchers in `erc721.ts`/`erc1155.ts`; the
  call sites already guard on the option being set.
- Extract `hasNonAddressArgs` and `addTodoAndCommentOut` into `zip-shared.ts`.
  The predicate was spelled out four times across the Foundry and Hardhat
  generators, and the TODO wording was duplicated between them.
  `addTodoAndCommentOut` now derives its wording from the contract instead of
  taking a boolean each caller had to re-derive.
- Collapse the two near-identical `getVariables` closures in `zip-foundry.ts`
  into one function parameterized by the address initializer, and hoist
  `withHelpers` out of the per-argument loop.
- Add a `manualNoticeTooltipProps` factory so the Superchain and crosschain
  incremental tooltips share their tippy configuration.
- Hoist the thrice-duplicated `crossChainLinkAllowOverride` description into a
  single constant.
- Replace the redundant `let x = false; $: { x = ... }` derived state in the
  token controls with a plain reactive assignment, and move the mid-script
  imports in `ERC721Controls.svelte` up to the import block.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V6YuEiAxTBpG1AMfF57Bqy
The single-case `switch` with a `const _: never` default in erc721.ts and
erc1155.ts is deliberate: it makes adding a bridging mode a compile error until
the new mode is handled here. Removing it as dead code lost that forcing
function.

The shared `addCrosschainLinked` extraction is kept — `addERC721Crosschain` and
`addERC1155Crosschain` remain as the per-kind wrappers the dispatch targets.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V6YuEiAxTBpG1AMfF57Bqy
Merging the two `getVariables` closures left `needsInitialOwnerVariable` and
`getLocalVariableType` with one caller each, and I inlined them on that basis.
That was the wrong call: those helpers exist to name a non-obvious condition,
not to avoid duplication, so inlining traded a readable predicate for a dense
inline expression.

Both are restored. The merged function body is now the original closure body
with only the address initializer swapped for the injected callback, which is
the diff this change should have been.

This also drops the `withHelpers(c)` hoist out of the loop. That was a
negligible saving on a once-per-download path, and keeping the per-argument
call avoids invoking it for contracts that have no non-address arguments.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V6YuEiAxTBpG1AMfF57Bqy
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution to OpenZeppelin Contracts Wizard. Before being able to integrate those changes, we would like you to sign our Contributor License Agreement.
You can sign the CLA by just posting a Pull Request Comment with the sentence below. Thanks.


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


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@ernestognw ernestognw left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, few nits after a quick pass. Thanks @ericglau

* Semantic version string representing of the minimum compatible version of Contracts to display in output.
*/
export const compatibleContractsSemver = '^5.6.0';
export const compatibleContractsSemver = '^5.7.0';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In inject-hyperlinks.ts, we get the version from openzeppelin-contracts-version.json. Shall we do it here too?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is intentionally kept separate. openzeppelin-contracts-version.json is the exact version we build and test against — it resolves to whatever the devDependency range installs, e.g. 5.7.1 from ^5.7.0 — whereas this semver describes the minimum version the generated code needs. Deriving one from the other would raise the stated minimum on every upstream patch release, and we may also want to bundle a newer version while the generated code stays compatible with an older one.

Comment thread packages/core/solidity/src/zip-shared.ts Outdated
Comment thread packages/core/solidity/src/account.ts Outdated
</ExpandableToggleRadio>

<ExpandableToggleRadio
label="Cross-Chain Bridging"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We use "cross-chain" in some sections and "crosschain" and others. Shall we standardize to "crosschain"?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agreed, we should standardize on "crosschain". Opened #831 to do it across all the tabs, since the mix exists in ERC20's shipped text too and this PR adds more of it.

Note that renaming ERC20's existing crossChain* option keys in the API would be breaking, so we kept the new options aligned with that naming — the same concept spelled two ways across tabs is a footgun for anything consuming the options API, especially LLMs filling these in via the MCP tools and AI assistant. #831 suggests updating user-facing labels but leaves the keys as-is.

Comment thread packages/ui/src/solidity/manual-notice-tooltip.ts Outdated
Co-authored-by: Ernesto García <ernestognw@gmail.com>
@ericglau
ericglau merged commit 89e9fab into OpenZeppelin:master Jul 31, 2026
21 of 22 checks passed
@ericglau
ericglau deleted the 57bridgeable branch July 31, 2026 18:08
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 31, 2026
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