Skip to content

Conversation

@ericglau
Copy link
Member

@ericglau ericglau commented Dec 1, 2025

Overview

In Solidity ERC-20's Cross-Chain Bridging section, adds an ERC-7866 Native option to use ERC20Crosschain. When this is selected, it also shows a sub-option Allow Link Overrides which defaults to false.

Both the ERC-7866 Native (ERC20Crosschain) and Custom (ERC20Bridgeable) bridging options will require access control.

Breaking Changes

Custom bridging option now requires access control to allow privileged roles to update the token bridge address after deployment.

Rationale: Tokens may want to update their bridge address to use a BridgeERC7802, which requires the token address as a constructor argument to set an immutable variable. This implies the token must be deployed before the bridge.

New Features

ERC-7786 Native (ERC20Crosschain) embeds an ERC-7786 based bridge directly in the token contract. This option requires access control to manage crosschain links.

  • Allow Link Overrides: When enabled, privileged roles can replace previously registered crosschain links. Defaults to false.

To do

  • Update to use openzeppelin-contracts master when ERC-7786 based crosschain bridge for ERC-20 tokens openzeppelin-contracts#5914 is merged.
  • Add changeset, note breaking changes requiring access control
  • When the next release of openzeppelin-contracts is available:
    • Update packages in
      • packages/core/solidity/package.json
      • packages/core/solidity/src/environments/hardhat/package.json
      • packages/core/solidity/src/environments/hardhat/upgradeable/package.json
      • yarn.lock
    • revert temporary remappings in:
      • packages/core/solidity/remappings.txt
      • packages/core/uniswap-hooks/remappings.txt
    • ensure tests pass after performing the above

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 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

This PR adds support for ERC-7786 native cross-chain bridging option across OpenZeppelin Wizard for ERC20, stablecoin, and Real World Asset contracts. It introduces a new crossChainLinkAllowOverride option, updates access control requirements to include the new bridging type, adds tokenBridge state management with setter functions, updates UI controls, and expands test coverage. It also updates build configuration to enable IR-based compilation and switches OpenZeppelin contracts dependency to the master branch.

Changes

Cohort / File(s) Summary
Changesets
\.changeset/ninety-ears-slide\.md, \.changeset/sad-cases-yawn\.md
Documents patch version bump and breaking/feature changes: ERC-7786 native bridging support, custom bridging now requires access control, new updateTokenBridgeAddress() function, and constructor parameter reordering.
Descriptions & Schemas
packages/common/src/ai/descriptions/solidity\.ts, packages/mcp/src/solidity/schemas\.ts, packages/ui/api/ai-assistant/function-definitions/solidity\.ts
Updated ERC20 descriptions to document ERC-7786 native option, added crossChainLinkAllowOverride field to schemas, and expanded crossChainBridging option set to include 'erc7786native'.
Core ERC20 Logic
packages/core/solidity/src/erc20\.ts
Extended cross-chain bridging options to include 'erc7786native', added crossChainLinkAllowOverride option flag, updated isAccessControlRequired logic, introduced addERC20Crosschain pathway, and enriched custom bridging with tokenBridge state management and setter functions.
ERC20 Generation & Stablecoin Logic
packages/core/solidity/src/generate/erc20\.ts, packages/core/solidity/src/generate/stablecoin\.ts, packages/core/solidity/src/stablecoin\.ts
Added crossChainLinkAllowOverride to ERC20 and stablecoin option generators with appropriate defaults, and refactored isAccessControlRequired to delegate to ERC20's implementation.
Build Configuration
packages/core/solidity/hardhat\.config\.js, packages/core/solidity/package\.json, packages/core/solidity/remappings\.txt, packages/core/solidity/src/environments/hardhat/(package\.json|upgradeable/package\.json), packages/uniswap-hooks/remappings\.txt
Added viaIR: true to hardhat optimizer settings, updated @openzeppelin/contracts dependency from ^5.5.0 to git master branch across multiple locations, and updated remappings to include @openzeppelin/contracts/contracts/ path.
Test Snapshots
packages/core/solidity/src/erc20\.test\.ts\.md, packages/core/solidity/src/zip-foundry\.test\.ts\.md
Updated contract inheritance order to include OwnableUpgradeable, added setTokenBridge() setter function with onlyOwner guard, adjusted constructor/initializer signatures to accept initialOwner, and modified parameter ordering in initialization sequences.
ERC20 Tests
packages/core/solidity/src/erc20\.test\.ts
Added test cases for ERC-7786 native bridging variants with combinations including allowOverride, ownable, roles, managed, and upgradeable patterns.
UI Controls
packages/ui/src/solidity/ERC20Controls\.svelte, packages/ui/src/solidity/StablecoinControls\.svelte, packages/ui/src/solidity/RealWorldAssetControls\.svelte
Added conditional showAllowOverride reactive flag, introduced "ERC-7786 Native" radio option under Cross-Chain Bridging, and conditionally renders "Allow Link Overrides" checkbox when ERC-7786 native is selected.
MCP Tools & Tests
packages/mcp/src/solidity/tools/(erc20|stablecoin|rwa)\.(ts|test\.ts)
Added crossChainLinkAllowOverride parameter to tool handlers and propagated into options objects; added corresponding test cases validating the new option combinations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • Key areas requiring close attention:
    • Core logic changes in packages/core/solidity/src/erc20.ts: new addERC20Crosschain bridging pathway, updated addCustomBridging with storage-based tokenBridge management, and access control logic updates.
    • Snapshot updates with inheritance reordering and parameter sequence changes in erc20.test.ts.md and zip-foundry.test.ts.md — verify no behavioral regressions and that test assertions align with new public signatures.
    • OpenZeppelin contracts dependency change from semver ^5.5.0 to git master branch — assess implications for reproducibility and stability across build environments.
    • Test coverage: verify new ERC-7786 native test cases exercise all combinations (allowOverride, access control, upgradeable variants) and that existing tests remain unbroken.

Possibly related PRs

  • Add Polkadot Solidity tab #650: Related through overlapping UI/code-generation surface modifications — both update ERC20/Stablecoin/RWA control files and function definitions to introduce or refine cross-chain bridging feature conditioning (superchain/erc7786native variants and option propagation patterns).

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 clearly and specifically describes the main feature being added: support for embedding ERC-7786 based crosschain bridge as a new ERC-20 option.
Description check ✅ Passed The PR description clearly documents the addition of ERC-7786 Native bridging option and breaking changes to custom bridging access control requirements, directly relating to the comprehensive changeset.

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

@socket-security
Copy link

socket-security bot commented Dec 1, 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:

  • css-tree@1.1.3
  • estraverse@5.3.0
  • resolve-from@5.0.0
  • ci-info@3.9.0
  • safe-buffer@5.1.2
  • uuid@9.0.1
  • escape-string-regexp@2.0.0
  • commander@2.20.3
  • isarray@1.0.0
  • ajv@6.12.6
  • imurmurhash@0.1.4
  • json-stable-stringify-without-jsonify@1.0.1
  • natural-compare@1.4.0
  • fast-json-stable-stringify@2.1.0
  • json-schema-traverse@0.4.1
  • uri-js@4.4.1
  • esrecurse@4.3.0
  • acorn-jsx@5.3.2
  • resolve-from@4.0.0
  • find-up@4.1.0
  • locate-path@5.0.0
  • resolve-cwd@3.0.0
  • signal-exit@3.0.7
  • p-limit@2.3.0
  • p-try@2.2.0
  • globby@11.1.0
  • node-fetch@2.7.0
  • process-nextick-args@2.0.1
  • string_decoder@1.1.1
  • normalize-url@6.1.0
  • commander@4.1.1
  • whatwg-url@5.0.0
  • tr46@0.0.3
  • webidl-conversions@3.0.1
  • retry@0.12.0
  • object-hash@3.0.0
  • eslint-visitor-keys@3.4.3
  • ieee754@1.2.1
  • @alloc/quick-lru@5.2.0
  • @humanwhocodes/module-importer@1.0.1
  • @popperjs/core@2.11.8
  • boolbase@1.0.0
  • commondir@1.0.1
  • content-type@1.0.5
  • cosmiconfig@7.1.0
  • css-select@4.3.0
  • cssesc@3.0.0
  • didyoumean@1.2.2
  • dlv@1.1.3
  • dom-serializer@1.4.1
  • domelementtype@2.3.0
  • domhandler@4.3.1
  • domutils@2.8.0
  • iconv-lite@0.6.3
  • entities@2.2.0
  • glob-parent@6.0.2
  • levn@0.4.1
  • prelude-ls@1.2.1
  • type-check@0.4.0
  • commander@7.2.0
  • graphemer@1.4.0
  • icss-utils@5.1.0
  • is-plain-object@5.0.0
  • isomorphic-unfetch@3.1.0
  • lilconfig@2.1.0
  • lodash.merge@4.6.2
  • escape-string-regexp@5.0.0
  • min-indent@1.0.1
  • normalize-range@0.1.2
  • nth-check@2.1.1
  • postcss-import@15.1.0
  • postcss-js@4.0.1
  • postcss-modules-values@4.0.0
  • postcss-value-parser@4.2.0
  • stack-utils@2.0.6
  • strip-bom@3.0.0
  • strip-indent@3.0.0
  • arg@5.0.2
  • unfetch@4.2.0
  • yaml@1.10.2
  • retry@0.13.1
  • colord@2.9.3
  • estree-walker@2.0.2
  • jest-worker@26.6.2
  • serialize-javascript@4.0.0
  • @trysound/sax@0.2.0
  • csso@4.2.0
  • mdn-data@2.0.14
  • stable@0.1.8
  • svgo@2.8.0
  • is-module@1.0.0
  • caniuse-api@3.0.0
  • cssnano-utils@3.1.0
  • postcss-calc@8.2.4
  • postcss-convert-values@5.1.3
  • postcss-discard-comments@5.1.2
  • postcss-discard-duplicates@5.1.0
  • postcss-discard-empty@5.1.1
  • postcss-discard-overridden@5.1.0
  • postcss-merge-longhand@5.1.7
  • postcss-minify-font-values@5.1.0
  • postcss-minify-gradients@5.1.1
  • postcss-minify-params@5.1.4
  • postcss-minify-selectors@5.2.1
  • postcss-normalize-charset@5.1.0
  • postcss-normalize-display-values@5.1.0
  • postcss-normalize-positions@5.1.1
  • postcss-normalize-repeat-style@5.1.1
  • postcss-normalize-string@5.1.0
  • postcss-normalize-timing-functions@5.1.0
  • postcss-normalize-unicode@5.1.1
  • postcss-normalize-url@5.1.0
  • postcss-normalize-whitespace@5.1.1
  • postcss-ordered-values@5.1.3
  • postcss-reduce-transforms@5.1.0
  • postcss-svgo@5.1.0
  • postcss-unique-selectors@5.1.1
  • rollup-plugin-terser@7.0.2
  • stylehacks@5.1.1
  • proper-lockfile@4.1.2
  • cssnano-preset-default@5.2.14
  • cssnano@5.1.15
  • postcss-colormin@5.3.1
  • postcss-merge-rules@5.1.4
  • postcss-reduce-initial@5.1.2
  • fraction.js@4.3.7
  • js-cookie@2.2.1
  • jsesc@3.0.2
  • css-declaration-sorter@6.4.1
  • @rollup/pluginutils@4.2.1
  • @types/json-schema@7.0.15
  • file-entry-cache@8.0.0
  • sucrase@3.35.0
  • globals@14.0.0
  • flat-cache@4.0.1
  • postcss-modules-extract-imports@3.1.0
  • optionator@0.9.4
  • esquery@1.6.0
  • postcss-nested@6.2.0
  • unicorn-magic@0.3.0
  • postcss-selector-parser@6.1.2
  • source-map-js@1.2.1
  • @eslint-community/regexpp@4.12.1
  • @humanfs/core@0.19.1
  • regjsparser@0.12.0
  • tslib@2.8.1
  • postcss-modules-scope@3.2.1
  • undici-types@6.21.0
  • lilconfig@3.1.3
  • jsesc@3.1.0
  • postcss-modules-local-by-default@4.2.0
  • jiti@1.21.7
  • resolve@1.22.10
  • is-generator-function@1.1.0
  • autoprefixer@10.4.21
  • @openzeppelin/community-contracts@0.0.1
  • solidity-ast@0.4.60
  • nanoid@3.3.11
  • ts-api-utils@2.1.0
  • @eslint/eslintrc@3.3.1
  • @babel/helper-validator-identifier@7.27.1
  • @babel/code-frame@7.27.1
  • @humanwhocodes/retry@0.4.3
  • strnum@2.1.1
  • ignore@7.0.5
  • shell-quote@1.8.3
  • @types/estree@1.0.8
  • eslint-visitor-keys@4.2.1
  • eslint-scope@8.4.0
  • espree@10.4.0
  • postcss@8.5.6
  • prettier@3.6.2
  • css-what@6.2.2
  • @jridgewell/trace-mapping@0.3.30
  • @types/semver@7.7.1
  • typescript@5.9.3
  • semver@7.7.3

View full report

args: [
{ name: 'gateway', type: 'address' },
{ name: 'counterpart', type: 'bytes memory' },
{ name: 'allowOverride', type: 'bool' },
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this should be an argument in the public function. The contract has to hardcode a value IIUC. CC @Amxx

Copy link
Contributor

@frangio frangio Dec 4, 2025

Choose a reason for hiding this comment

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

From @Amxx: allowOverride should be false by default so that links are immutable once set.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also consider adding a comment explaining the choice of false and when to consider changing it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added an option for this with default as false.

@frangio
Copy link
Contributor

frangio commented Dec 4, 2025

I think "ERC-7786 Native" instead of "Embedded" is a clearer and more compelling name.

Open to other suggestions involving ERC-7786.

@socket-security
Copy link

socket-security bot commented Dec 4, 2025

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

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedrollup-plugin-terser@​7.0.210010010050100
Added@​types/​semver@​7.7.11001007581100
Addedpostcss@​8.5.61001008284100
Addedautoprefixer@​10.4.211001009286100
Addedsemver@​7.7.310010010087100
Addedtypescript@​5.9.31001009010090
Addedprettier@​3.6.29910010098100
Added@​openzeppelin/​community-contracts@​0.0.1100100100100100

View full report

@ericglau ericglau requested a review from frangio December 4, 2025 23:20
@ericglau ericglau marked this pull request as ready for review December 5, 2025 20:30
@ericglau ericglau requested review from a team as code owners December 5, 2025 20:30
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: 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/hardhat.config.js (1)

32-40: Potential off-by-one bug when chunking compilationJobs

The loop condition i < compilationJobs.length - 1 will drop the last job when compilationJobs.length > CHUNK_SIZE (e.g., length 101 → job at index 100 is never included in any chunk).

Consider iterating up to the full length instead:

 task(TASK_COMPILE_SOLIDITY_MERGE_COMPILATION_JOBS, async ({ compilationJobs }, _, runSuper) => {
   const CHUNK_SIZE = 100;
   const chunks = [];
-  for (let i = 0; i < compilationJobs.length - 1; i += CHUNK_SIZE) {
+  for (let i = 0; i < compilationJobs.length; i += CHUNK_SIZE) {
     chunks.push(compilationJobs.slice(i, i + CHUNK_SIZE));
   }
   const mergedChunks = await Promise.all(chunks.map(cj => runSuper({ compilationJobs: cj })));
   return mergedChunks.flat();
 });

This avoids skipping the tail of the array when there are more than CHUNK_SIZE jobs.

🧹 Nitpick comments (3)
packages/core/solidity/src/generate/stablecoin.ts (1)

22-23: Stablecoin presets correctly surface crossChainLinkAllowOverride

Wiring crossChainLinkAllowOverride into both basic (false) and full (true) presets keeps the generator aligned with the Stablecoin options type and the new ERC-7786-native flow. If, in the future, you want to forbid allowOverride for non‑erc7786native modes, this would be the place to specialize those combinations.

Also applies to: 40-42

packages/core/solidity/src/zip-foundry.test.ts.md (1)

394-397: Consider tightening or documenting setTokenBridge behavior

setTokenBridge lets the owner set the bridge to any address (including zero) without emitting an event. If disabling the bridge via zero is not desired, mirroring the non‑zero require from initialize and/or emitting a TokenBridgeSet event would make misconfiguration and upgrades easier to audit; otherwise, a short comment that zero is allowed to disable bridging would clarify intent.

packages/core/solidity/package.json (1)

31-31: Avoid long‑term dependency on @openzeppelin/contracts master

Pointing @openzeppelin/contracts at git+https://github.com/OpenZeppelin/openzeppelin-contracts.git#master is reasonable while you depend on unreleased ERC‑7786 changes, but it makes builds non‑reproducible as master evolves. For anything beyond a short transitional window, consider pinning to a specific commit hash and then switching back to a tagged version once the target release is available.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d0b1b84 and c708432.

⛔ Files ignored due to path filters (3)
  • packages/core/solidity/src/erc20.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/zip-foundry.test.ts.snap is excluded by !**/*.snap
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (27)
  • .changeset/ninety-ears-slide.md (1 hunks)
  • .changeset/sad-cases-yawn.md (1 hunks)
  • packages/common/src/ai/descriptions/solidity.ts (1 hunks)
  • packages/core/solidity/hardhat.config.js (1 hunks)
  • packages/core/solidity/package.json (2 hunks)
  • packages/core/solidity/remappings.txt (1 hunks)
  • packages/core/solidity/src/environments/hardhat/package.json (1 hunks)
  • packages/core/solidity/src/environments/hardhat/upgradeable/package.json (1 hunks)
  • packages/core/solidity/src/erc20.test.ts (1 hunks)
  • packages/core/solidity/src/erc20.test.ts.md (12 hunks)
  • packages/core/solidity/src/erc20.ts (10 hunks)
  • packages/core/solidity/src/generate/erc20.ts (1 hunks)
  • packages/core/solidity/src/generate/stablecoin.ts (2 hunks)
  • packages/core/solidity/src/stablecoin.ts (2 hunks)
  • packages/core/solidity/src/zip-foundry.test.ts.md (5 hunks)
  • packages/core/uniswap-hooks/remappings.txt (1 hunks)
  • packages/mcp/src/solidity/schemas.ts (1 hunks)
  • packages/mcp/src/solidity/tools/erc20.test.ts (2 hunks)
  • packages/mcp/src/solidity/tools/erc20.ts (2 hunks)
  • packages/mcp/src/solidity/tools/rwa.test.ts (2 hunks)
  • packages/mcp/src/solidity/tools/rwa.ts (2 hunks)
  • packages/mcp/src/solidity/tools/stablecoin.test.ts (2 hunks)
  • packages/mcp/src/solidity/tools/stablecoin.ts (2 hunks)
  • packages/ui/api/ai-assistant/function-definitions/solidity.ts (1 hunks)
  • packages/ui/src/solidity/ERC20Controls.svelte (2 hunks)
  • packages/ui/src/solidity/RealWorldAssetControls.svelte (2 hunks)
  • packages/ui/src/solidity/StablecoinControls.svelte (2 hunks)
🧰 Additional context used
🧠 Learnings (16)
📓 Common learnings
Learnt from: ernestognw
Repo: OpenZeppelin/contracts-wizard PR: 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.
Learnt from: typicalHuman
Repo: OpenZeppelin/contracts-wizard PR: 715
File: packages/core/solidity/src/stablecoin.ts:74-77
Timestamp: 2025-11-03T12:18:33.779Z
Learning: In packages/core/solidity/src/stablecoin.ts, the ERC20Restricted base contract from openzeppelin/community-contracts provides a default implementation of isUserAllowed that returns true for non-BLOCKED users (blocklist logic). Only allowlist mode needs to override isUserAllowed to check for Restriction.ALLOWED instead. Blocklist mode uses the default implementation without override.
📚 Learning: 2025-11-03T12:18:33.779Z
Learnt from: typicalHuman
Repo: OpenZeppelin/contracts-wizard PR: 715
File: packages/core/solidity/src/stablecoin.ts:74-77
Timestamp: 2025-11-03T12:18:33.779Z
Learning: In packages/core/solidity/src/stablecoin.ts, the ERC20Restricted base contract from openzeppelin/community-contracts provides a default implementation of isUserAllowed that returns true for non-BLOCKED users (blocklist logic). Only allowlist mode needs to override isUserAllowed to check for Restriction.ALLOWED instead. Blocklist mode uses the default implementation without override.

Applied to files:

  • packages/ui/src/solidity/StablecoinControls.svelte
  • packages/ui/src/solidity/ERC20Controls.svelte
  • packages/mcp/src/solidity/tools/rwa.test.ts
  • packages/mcp/src/solidity/tools/stablecoin.ts
  • packages/mcp/src/solidity/tools/erc20.test.ts
  • packages/core/solidity/src/erc20.test.ts.md
  • packages/ui/src/solidity/RealWorldAssetControls.svelte
  • packages/mcp/src/solidity/tools/rwa.ts
  • packages/mcp/src/solidity/tools/stablecoin.test.ts
  • packages/core/solidity/src/generate/stablecoin.ts
  • packages/core/solidity/src/generate/erc20.ts
  • packages/core/solidity/src/stablecoin.ts
  • packages/core/solidity/src/erc20.ts
📚 Learning: 2025-08-15T22:49:25.653Z
Learnt from: ernestognw
Repo: OpenZeppelin/contracts-wizard PR: 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:

  • packages/core/uniswap-hooks/remappings.txt
  • packages/core/solidity/package.json
  • packages/core/solidity/src/environments/hardhat/upgradeable/package.json
  • packages/core/solidity/src/environments/hardhat/package.json
  • .changeset/ninety-ears-slide.md
  • packages/core/solidity/remappings.txt
  • .changeset/sad-cases-yawn.md
  • packages/core/solidity/src/erc20.ts
  • packages/core/solidity/src/zip-foundry.test.ts.md
📚 Learning: 2025-08-19T15:18:09.410Z
Learnt from: ericglau
Repo: OpenZeppelin/contracts-wizard PR: 638
File: packages/core/cairo_alpha/src/scripts/update-scarb-project.ts:62-79
Timestamp: 2025-08-19T15:18:09.410Z
Learning: In the cairo_alpha package (packages/core/cairo_alpha), the OpenZeppelin dependency in test_project/Scarb.toml is expected to be in { git, tag } form rather than a simple registry-style string, so the update script only needs to update the tag value, not convert between formats.

Applied to files:

  • packages/core/solidity/package.json
  • packages/core/solidity/src/environments/hardhat/upgradeable/package.json
  • packages/core/solidity/src/environments/hardhat/package.json
  • packages/core/solidity/remappings.txt
📚 Learning: 2025-09-12T15:07:08.673Z
Learnt from: ericglau
Repo: OpenZeppelin/contracts-wizard PR: 663
File: packages/core/cairo_alpha/src/custom.test.ts.md:12-12
Timestamp: 2025-09-12T15:07:08.673Z
Learning: In the OpenZeppelin contracts-wizard cairo_alpha package changelog (packages/core/cairo_alpha/CHANGELOG.md), each alpha version gets its own separate entry under the "Unreleased" section rather than updating a single entry. This allows tracking of changes across different alpha releases (e.g., v3.0.0-alpha.0, v3.0.0-alpha.1, v3.0.0-alpha.2 all have separate entries).

Applied to files:

  • packages/core/solidity/package.json
  • packages/core/solidity/src/environments/hardhat/upgradeable/package.json
  • packages/core/solidity/src/environments/hardhat/package.json
  • .changeset/ninety-ears-slide.md
  • packages/core/solidity/remappings.txt
📚 Learning: 2025-10-22T16:23:53.055Z
Learnt from: ericglau
Repo: OpenZeppelin/contracts-wizard PR: 680
File: packages/core/solidity/src/environments/hardhat/polkadot/package.json:17-17
Timestamp: 2025-10-22T16:23:53.055Z
Learning: In packages/core/solidity/src/environments/hardhat/polkadot/package.json, the "license" field is a placeholder that gets dynamically overwritten with the actual contract license when packaging the JSON into the zip file during zip generation.

Applied to files:

  • packages/core/solidity/package.json
  • packages/core/solidity/src/environments/hardhat/upgradeable/package.json
  • packages/core/solidity/src/environments/hardhat/package.json
📚 Learning: 2025-09-12T20:50:43.101Z
Learnt from: CoveMB
Repo: OpenZeppelin/contracts-wizard PR: 644
File: packages/ui/api/services/open-ai.ts:43-56
Timestamp: 2025-09-12T20:50:43.101Z
Learning: In the OpenZeppelin contracts-wizard project, the current streaming implementation in packages/ui/api/services/open-ai.ts intentionally handles text deltas and function_calls with different formats (raw text chunks vs JSON objects). While this can cause JSON.parse issues, harmonizing the response format is considered outside scope of dependency updates as it requires UI refactoring to handle unified streaming responses.

Applied to files:

  • packages/core/solidity/package.json
📚 Learning: 2025-08-19T15:21:06.991Z
Learnt from: ericglau
Repo: OpenZeppelin/contracts-wizard PR: 638
File: packages/core/cairo_alpha/src/account.test.ts.md:18-18
Timestamp: 2025-08-19T15:21:06.991Z
Learning: In the OpenZeppelin contracts-wizard repository, the cairo_alpha package (packages/core/cairo_alpha) and the stable cairo package (packages/core/cairo) are separate implementations that do not need to have the same code or matching dependency versions. The cairo_alpha package targets dependencies that are either newer than or the same as the stable cairo package, allowing it to test and support newer Cairo/Scarb/OpenZeppelin versions while the stable version maintains compatibility with stable releases.

Applied to files:

  • packages/core/solidity/package.json
  • packages/core/solidity/src/environments/hardhat/upgradeable/package.json
  • packages/core/solidity/src/environments/hardhat/package.json
📚 Learning: 2025-09-18T20:17:09.709Z
Learnt from: ericglau
Repo: OpenZeppelin/contracts-wizard PR: 652
File: packages/mcp/src/confidential/schemas.ts:40-46
Timestamp: 2025-09-18T20:17:09.709Z
Learning: MCP tool schemas for confidential contracts can be more restrictive than the core API. For the votes field in confidential fungible tokens, the MCP schema only accepts 'blocknumber' or 'timestamp' strings because undefined behaves functionally equivalent to false, eliminating the need to explicitly accept boolean values in the tool definition.

Applied to files:

  • packages/mcp/src/solidity/tools/rwa.test.ts
  • packages/mcp/src/solidity/tools/erc20.test.ts
  • packages/mcp/src/solidity/schemas.ts
  • packages/mcp/src/solidity/tools/stablecoin.test.ts
📚 Learning: 2025-08-20T20:23:30.259Z
Learnt from: ericglau
Repo: OpenZeppelin/contracts-wizard PR: 609
File: packages/core/solidity/src/set-upgradeable.ts:0-0
Timestamp: 2025-08-20T20:23:30.259Z
Learning: In OpenZeppelin contracts-wizard, upgradeable contracts use two different strategies for Initializable imports: Account contracts directly import from contracts-upgradeable/proxy/utils/Initializable.sol for explicit clarity, while other upgradeable contracts (ERC20, ERC721, Governor, etc.) use helpers to automatically transpile imports to upgradeable versions. This architectural separation is intentional due to the special ERC-4337 requirements of account contracts.

Applied to files:

  • packages/core/solidity/src/environments/hardhat/upgradeable/package.json
  • packages/core/solidity/remappings.txt
  • packages/core/solidity/src/erc20.test.ts.md
  • packages/core/solidity/src/zip-foundry.test.ts.md
📚 Learning: 2025-08-19T01:15:58.945Z
Learnt from: ernestognw
Repo: OpenZeppelin/contracts-wizard PR: 609
File: packages/core/solidity/src/signer.ts:45-49
Timestamp: 2025-08-19T01:15:58.945Z
Learning: The OpenZeppelin contracts-upgradeable package includes upgradeable versions of signer contracts like SignerECDSAUpgradeable, SignerP256Upgradeable, SignerRSAUpgradeable, MultiSignerERC7913Upgradeable, and MultiSignerERC7913WeightedUpgradeable in the contracts/utils/cryptography/signers directory.

Applied to files:

  • packages/core/solidity/remappings.txt
  • packages/core/solidity/src/erc20.test.ts.md
  • packages/core/solidity/src/zip-foundry.test.ts.md
📚 Learning: 2025-08-19T01:15:58.945Z
Learnt from: ernestognw
Repo: OpenZeppelin/contracts-wizard PR: 609
File: packages/core/solidity/src/signer.ts:45-49
Timestamp: 2025-08-19T01:15:58.945Z
Learning: All OpenZeppelin signer contracts have upgradeable variants available in the contracts-upgradeable package: SignerECDSAUpgradeable, SignerP256Upgradeable, SignerRSAUpgradeable, MultiSignerERC7913Upgradeable, and MultiSignerERC7913WeightedUpgradeable all exist in contracts/utils/cryptography/signers/ directory.

Applied to files:

  • packages/core/solidity/remappings.txt
  • packages/core/solidity/src/erc20.test.ts.md
  • packages/core/solidity/src/zip-foundry.test.ts.md
📚 Learning: 2025-08-21T19:44:06.797Z
Learnt from: ericglau
Repo: OpenZeppelin/contracts-wizard PR: 609
File: packages/core/solidity/src/account.ts:191-204
Timestamp: 2025-08-21T19:44:06.797Z
Learning: Initializable is available in both openzeppelin/contracts and openzeppelin/contracts-upgradeable packages, so conditional imports like `openzeppelin/${opts.upgradeable ? 'contracts-upgradeable' : 'contracts'}/proxy/utils/Initializable.sol` are valid and will resolve correctly.

Applied to files:

  • packages/core/solidity/remappings.txt
  • packages/core/solidity/src/erc20.test.ts.md
  • packages/core/solidity/src/zip-foundry.test.ts.md
📚 Learning: 2025-09-18T20:18:23.799Z
Learnt from: ericglau
Repo: OpenZeppelin/contracts-wizard PR: 652
File: packages/ui/api/ai-assistant/function-definitions/confidential.ts:32-38
Timestamp: 2025-09-18T20:18:23.799Z
Learning: In OpenZeppelin Wizard, the AI Assistant defines its own function definitions separately and does not use the MCP tools. This means the AI Assistant function definitions and MCP schemas can have different shapes without causing validation conflicts.

Applied to files:

  • packages/ui/api/ai-assistant/function-definitions/solidity.ts
📚 Learning: 2025-08-15T22:52:34.129Z
Learnt from: ernestognw
Repo: OpenZeppelin/contracts-wizard PR: 609
File: packages/core/solidity/src/account.ts:89-0
Timestamp: 2025-08-15T22:52:34.129Z
Learning: In OpenZeppelin contracts-wizard, non-upgradeable accounts still require initializer logic (Initializable, _disableInitializers(), and initialize() function) because ERC-4337 accounts are typically deployed by factories as minimal clone proxies, which cannot use constructors effectively for initialization. This is the intended deployment pattern for ERC-4337 account abstraction, even for non-upgradeable accounts.

Applied to files:

  • packages/core/solidity/src/erc20.test.ts.md
  • packages/core/solidity/src/zip-foundry.test.ts.md
📚 Learning: 2025-08-15T23:23:13.097Z
Learnt from: ernestognw
Repo: OpenZeppelin/contracts-wizard PR: 609
File: packages/core/solidity/src/signer.ts:31-38
Timestamp: 2025-08-15T23:23:13.097Z
Learning: In OpenZeppelin contracts-wizard, the `setUpgradeableAccount` function deliberately sets `c.upgradeable = false` after upgradeable setup to exclude EIP712Upgradeable and ERC7739Upgradeable variants (avoiding per-call SLOAD overhead). This architectural pattern necessitates manual `_disableInitializers()` setup in both account.ts and signer.ts since the standard upgradeable constructor logic doesn't apply when upgradeability is disabled post-setup.

Applied to files:

  • packages/core/solidity/src/erc20.test.ts.md
  • packages/core/solidity/src/erc20.ts
  • packages/core/solidity/src/zip-foundry.test.ts.md
🧬 Code graph analysis (3)
packages/mcp/src/solidity/tools/rwa.test.ts (1)
packages/mcp/src/helpers.test.ts (1)
  • assertAPIEquivalence (46-88)
packages/ui/api/ai-assistant/function-definitions/solidity.ts (3)
packages/ui/api/ai-assistant/types/helpers.ts (1)
  • extractStringEnumValues (107-110)
packages/core/solidity/src/erc20.ts (1)
  • CrossChainBridging (20-20)
packages/common/src/ai/descriptions/solidity.ts (1)
  • solidityERC20Descriptions (25-40)
packages/mcp/src/solidity/tools/stablecoin.test.ts (1)
packages/mcp/src/helpers.test.ts (1)
  • assertAPIEquivalence (46-88)
🔇 Additional comments (34)
packages/core/solidity/hardhat.config.js (1)

61-71: viaIR: true placement looks correct; verify compiler/Hardhat support and CI impact

Adding viaIR: true as a sibling to optimizer under solidity.settings matches the expected compiler config shape and is consistent with using the IR pipeline for all Solidity compilation here.

Please double‑check that:

  • The SOLIDITY_VERSION in ./src/solidity-version.json and the Hardhat version in this repo both support viaIR.
  • CI still passes across all targets (including any older sample projects) with the IR pipeline enabled globally.

If everything is green in CI, this change seems fine to ship.

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

44-46: Reuse of ERC20 access-control helper looks good

Delegating to erc20isAccessControlRequired and then OR-ing restrictions / freezable keeps stablecoin in sync with ERC20’s evolving requirements (e.g., new cross-chain modes) while still enforcing its own extension-specific constraints.

packages/core/uniswap-hooks/remappings.txt (1)

1-1: @openzeppelin/contracts remapping is consistent

Pointing the alias to node_modules/@openzeppelin/contracts/contracts/ matches the pattern used in other remapping files and aligns with the import paths in the snapshots.

packages/core/solidity/src/zip-foundry.test.ts.md (4)

320-324: Script updated to match new initializer ordering

The Foundry script now encodes (tokenBridge_, initialOwner, recipient) for MyToken.initialize, which matches the contract signature below; deployment scaffolding stays consistent.


348-348: Inheritance order change is still sound

Moving OwnableUpgradeable earlier in the base list (while keeping Initializable first) preserves a valid linearization alongside the ERC20, bridgeable, and UUPS bases; no override conflicts are apparent.


364-375: Initializer now cleanly separates owner and recipient

The new initialize(address tokenBridge_, address initialOwner, address recipient) plus __Ownable_init(initialOwner) keeps the tokenBridge non‑zero requirement and chain‑specific premint while decoupling ownership from the recipient address. This looks correct.


448-453: Test fixture aligns with new initializer signature

The UUPS ERC20 test now deploys the proxy using (tokenBridge_, initialOwner, recipient) in the same order as the updated initialize function, so the snapshot remains consistent end‑to‑end.

packages/mcp/src/solidity/tools/rwa.test.ts (1)

41-49: RWA MCP tests correctly exercise crossChainLinkAllowOverride

Adding the crosschain erc7786native allowOverrides case and wiring crossChainLinkAllowOverride into the “all” scenario ensures the MCP schema and tool stay aligned with StablecoinOptions and the new ERC‑7786 native bridging behavior.

Also applies to: 65-66

packages/mcp/src/solidity/tools/erc20.test.ts (1)

41-49: ERC20 MCP tests cover ERC‑7786 allowOverrides path

The added crosschain erc7786native allowOverrides test plus the crossChainLinkAllowOverride: false field in the “all” case give good coverage that the MCP schema exposes the new flag and that it round‑trips correctly through erc20.print.

Also applies to: 65-66

packages/core/solidity/remappings.txt (1)

3-3: Core remapping for @openzeppelin/contracts looks correct

Adding @openzeppelin/contracts/=node_modules/@openzeppelin/contracts/contracts/ is consistent with the other entries here and with how the generated Solidity imports are written.

packages/core/solidity/src/erc20.test.ts (1)

171-206: ERC-7786 native combinations are well covered

The new snapshot cases exercise the main erc7786native variants (base, allowOverride, access modes, and upgradeable) and look consistent with existing crossChainBridging coverage. No issues from the test wiring side.

packages/core/solidity/src/environments/hardhat/upgradeable/package.json (1)

13-13: Git master dependency is fine as a temporary measure

Pointing @openzeppelin/contracts to the master branch matches the PR’s intent to consume unreleased ERC-7786 features. Since this reduces reproducibility, just ensure this is reverted to a tagged release when the corresponding contracts version is published, as already noted in the PR checklist.

packages/ui/src/solidity/ERC20Controls.svelte (1)

54-57: UI wiring for ERC-7786 Native and Allow Link Overrides looks correct

The reactive showAllowOverride flag and the new ERC-7786 Native radio/checkbox correctly bind to opts.crossChainBridging and opts.crossChainLinkAllowOverride, with tooltips pointing to the right docs. Behavior is consistent with existing Superchain controls.

Also applies to: 195-211

packages/ui/src/solidity/StablecoinControls.svelte (1)

53-56: Stablecoin ERC-7786 Native controls are consistent and correctly bound

The new ERC-7786 Native option and conditional Allow Link Overrides checkbox correctly mirror the ERC20 UI behavior and bind to the expected Stablecoin options. No issues spotted.

Also applies to: 229-245

packages/mcp/src/solidity/tools/stablecoin.test.ts (1)

41-49: MCP Stablecoin tests correctly cover crossChainLinkAllowOverride

The new erc7786native allowOverrides test and the explicit crossChainLinkAllowOverride: false in the “all” case properly exercise the new option through the MCP path and keep the DeepRequired typing in sync with StablecoinOptions. Looks good.

Also applies to: 65-65

packages/core/solidity/src/environments/hardhat/package.json (1)

13-13: Consistent switch to contracts master for the non-upgradeable Hardhat env

Aligning this env with the upgradeable one by using git+https://github.com/OpenZeppelin/openzeppelin-contracts.git#master is reasonable for testing unreleased features. Just confirm you’ll move back to a tagged version once the next contracts release is out.

packages/mcp/src/solidity/tools/erc20.ts (1)

26-27: ERC20 MCP tool correctly propagates crossChainLinkAllowOverride

The new crossChainLinkAllowOverride parameter is cleanly threaded from the tool input into ERC20Options and on to erc20.print, matching the patterns used for other ERC20 options. No issues here.

Also applies to: 44-45

packages/core/solidity/src/generate/erc20.ts (1)

23-23: Generator blueprint now accounts for crossChainLinkAllowOverride

Adding crossChainLinkAllowOverride: [false] keeps generateERC20Options aligned with the updated ERC20Options shape and ensures all generated combinations explicitly set the new flag. This fits well with dedicated tests that cover the true case.

packages/ui/src/solidity/RealWorldAssetControls.svelte (2)

55-59: LGTM!

The reactive block correctly tracks when to show the Allow Link Overrides option based on the ERC-7786 native bridging selection.


236-252: LGTM!

The new ERC-7786 Native radio option and conditional Allow Link Overrides checkbox follow the established UI patterns in this file and are consistent with similar implementations in ERC20Controls.svelte and StablecoinControls.svelte.

packages/mcp/src/solidity/tools/rwa.ts (1)

26-26: LGTM!

The crossChainLinkAllowOverride option is correctly wired through the destructured parameters and propagated into the StablecoinOptions object, consistent with the schema definition where rwaSchema = stablecoinSchema.

Also applies to: 45-45

packages/mcp/src/solidity/schemas.ts (1)

66-72: LGTM!

The schema correctly extends crossChainBridging with the new 'erc7786native' option and adds the crossChainLinkAllowOverride boolean field. The inheritance via erc20SchemaOmitUpgradeablestablecoinSchemarwaSchema ensures consistency across all token types.

packages/mcp/src/solidity/tools/stablecoin.ts (1)

26-26: LGTM!

The crossChainLinkAllowOverride option is correctly wired through the stablecoin tool, consistent with the ERC20 and RWA tool implementations.

Also applies to: 45-45

packages/common/src/ai/descriptions/solidity.ts (1)

33-36: LGTM!

The descriptions are clear and comprehensive. The crossChainBridging description now accurately covers all three options (custom, ERC-7786 native, and SuperchainERC20), and the new crossChainLinkAllowOverride description properly documents its conditional applicability.

.changeset/sad-cases-yawn.md (1)

1-7: Verify version bump type for breaking changes.

The changeset uses patch version bumps, but the description documents breaking changes (access control requirement, constructor parameter order changes). Based on learnings from this repo, breaking changes with concrete migration paths can use minor bumps instead of major, but a patch seems too conservative for breaking changes.

Consider whether this should be a minor bump instead of patch given the breaking changes to the custom bridging option.

packages/ui/api/ai-assistant/function-definitions/solidity.ts (1)

60-70: LGTM!

The new erc7786native option and crossChainLinkAllowOverride property are correctly added to the AI function definition. The enum values are properly extracted using extractStringEnumValues<CrossChainBridging>() maintaining type safety, and the description is correctly sourced from the common descriptions catalog. This is consistent with the existing pattern used for other properties.

packages/core/solidity/src/erc20.test.ts.md (4)

723-749: LGTM! New ERC-7786 native bridging test snapshots.

The new test snapshots for erc7786native bridging correctly demonstrate:

  • Import of ERC20Crosschain and CrosschainLinked
  • Constructor accepting CrosschainLinked.Link[] memory links
  • Access-controlled setLink function with _setLink(gateway, counterpart, false) by default
  • Proper inheritance chain with access control (Ownable)

751-777: LGTM! Allow override variant correctly hardcodes true.

The allowOverride variant snapshot correctly shows _setLink(gateway, counterpart, true) which aligns with the past review discussion that allowOverride should be hardcoded in the contract rather than passed as a function argument.


549-570: LGTM! Breaking change to custom bridging correctly applied.

The custom bridging snapshot now correctly includes:

  • Ownable import and inheritance (breaking change as documented)
  • initialOwner constructor parameter
  • New setTokenBridge public function with onlyOwner modifier

This aligns with the PR objectives stating custom bridging now requires access control.


903-939: Remove or investigate the source of CrosschainLinked type reference.

CrosschainLinked does not exist in OpenZeppelin's official contracts or contracts-upgradeable packages. The review snapshot uses CrosschainLinked.Link[] but imports only CrosschainLinkedUpgradeable, which itself appears to be non-existent in OpenZeppelin. Verify whether this is an experimental feature, a custom type for contracts-wizard, or whether the test snapshot should use standard OpenZeppelin cross-chain types like ERC7786Receiver or CrossChainEnabled instead.

Likely an incorrect or invalid review comment.

packages/core/solidity/src/erc20.ts (4)

390-433: setTokenBridge only added for ownable access mode.

The setTokenBridge function is added for ownable access (both upgradeable and non-upgradeable paths), but not for roles or managed access modes. For roles, the bridge is managed via TOKEN_BRIDGE_ROLE grants/revokes, and for managed, via the authority. This is likely intentional since role-based systems don't need a separate setter, but confirm this design choice.


341-357: LGTM! ERC-7786 native bridging implementation.

The addERC20Crosschain function correctly:

  • Adds the ERC20Crosschain parent contract
  • Sets up CrosschainLinked with links constructor argument
  • Uses requireAccessControl to protect setLink with the CROSSCHAIN_LINKER role
  • Hardcodes crossChainLinkAllowOverride in the function body as requested in past reviews

551-563: LGTM! New function definitions added.

The setTokenBridge and setLink function definitions are correctly structured with appropriate argument types (address for tokenBridge, address and bytes memory for gateway/counterpart).


84-92: LGTM! Access control requirement logic updated.

The isAccessControlRequired function correctly includes 'erc7786native' alongside 'custom' as bridging options that require access control. This ensures the UI and validation logic properly enforces access control for both bridging modes.

@ericglau
Copy link
Member Author

ericglau commented Dec 8, 2025

@SocketSecurity ignore-all
Looks like false positives

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";␊
contract MyToken is ERC20, ERC20Bridgeable, ERC20Permit {␊
contract MyToken is ERC20, ERC20Bridgeable, Ownable, ERC20Permit {␊
Copy link
Contributor

@Amxx Amxx Dec 8, 2025

Choose a reason for hiding this comment

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

What would it take to join the ERC20XXX inheritance and have Ownable at the end. Not really an issue, but it would be cleaner if we could achieve that easily

Copy link
Member Author

@ericglau ericglau Dec 8, 2025

Choose a reason for hiding this comment

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

I started to do this but realized that would make it have a different order than the parent initializer calls. We document that the parent initializer calls should be in linearization order, and the Upgrades Plugins would give a warning if they are not.

We should aim to eventually stabilize and reorganize these, but it may require a larger change in how the code is generated in order to do this properly.

Opened #750 to track this as an enhancement request.

ericglau and others added 2 commits December 8, 2025 11:30
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
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.

3 participants