Skip to content

Conversation

ernestognw
Copy link
Member

@ernestognw ernestognw commented Jul 25, 2025

Fixes #618

Copy link

socket-security bot commented Aug 8, 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

@ericglau
Copy link
Member

ericglau commented Aug 8, 2025

Merged with master and #619. We may need to also merge with #577 to handle upgradeable signers, since the signers in Contracts 5.4.0 require constructors.

Copy link
Contributor

coderabbitai bot commented Aug 12, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Threads upgradeability through account generation, signer wiring, tooling, UI, schemas, and zip generators; replaces a single upgradeable flag with granular contract flags and initializer-aware logic; migrates Account and signer imports to OpenZeppelin Contracts 5.4.0; adds UI controls and schema/support for upgradeable accounts.

Changes

Cohort / File(s) Summary
Changesets
./.changeset/*
Adds changeset entries documenting minor bumps, migration to OZ Contracts 5.4.0, new signer constructors, and upgradeability notes.
Core — Account builder & signer wiring
packages/core/solidity/src/account.ts, packages/core/solidity/src/signer.ts, packages/core/solidity/src/set-upgradeable.ts, packages/core/solidity/src/generate/account.ts
Wires opts.upgradeable through account generation; adds setUpgradeableAccount; updates signer import paths to OpenZeppelin Contracts 5.4.0; introduces signerArgs; changes addSigner signature to accept upgradeable; adds initializer vs constructor wiring for upgradeable signers and multisig locking/initializer plumbing.
Core — Contract model, printing & options
packages/core/solidity/src/contract.ts, packages/core/solidity/src/options.ts, packages/core/solidity/src/print.ts
Replaces upgradeable with flags (shouldAutoTranspileImports, shouldInstallContractsUpgradeable, shouldUseUpgradesPluginsForProxyDeployment); adds constructorComments; renames gating to shouldUseInitializers; adapts constructor/initializer emission and parent-transpilation logic.
Zip generators & tests / snapshots
packages/core/solidity/src/zip-foundry.ts, packages/core/solidity/src/zip-hardhat.ts, packages/core/solidity/src/zip-foundry.test.ts, packages/core/solidity/src/zip-foundry.test.ts.md, packages/core/solidity/src/zip-hardhat.test.ts, packages/core/solidity/src/zip-hardhat.test.ts.md
Adds flags controlling plugin-based proxy deployment and upgradeable package installs; conditions remappings/install steps; generates proxy vs direct deployment paths; adds Account test cases and snapshots (non-upgradeable and upgradeable).
MCP: schema & tooling
packages/mcp/src/solidity/schemas.ts, packages/mcp/src/solidity/tools/account.ts, packages/mcp/src/solidity/tools/account.test.ts
Adds optional upgradeable to accountSchema; propagates upgradeable into tooling and tests.
UI: Account controls & Upgradeability UI
packages/ui/src/solidity/AccountControls.svelte, packages/ui/src/solidity/UpgradeabilitySection.svelte, packages/ui/src/solidity/App.svelte
Renders UpgradeabilitySection, adds disabled/disabledReason props, disables upgrade option for ERC7702, updates help links/labels, removes Account experimental marker for downloads/actions.
API / AI function defs & descriptions
packages/ui/api/ai-assistant/function-definitions/solidity.ts, packages/common/src/ai/descriptions/solidity.ts
Adds upgradeable to Account AI function parameters and simplifies the Account prompt text.
Helpers & utilities
packages/core/solidity/src/helpers.ts, packages/core/solidity/src/set-upgradeable.ts
Adds makeUpgradeable helper and setUpgradeableAccount for account-specific upgrade wiring and import selection.
Foundry / Hardhat packaging flags
packages/core/solidity/src/zip-foundry.ts, packages/core/solidity/src/zip-hardhat.ts, packages/core/solidity/src/contract.ts
Introduces shouldUseUpgradesPluginsForProxyDeployment and shouldInstallContractsUpgradeable flags; conditions remappings, install steps, and deployment script generation.
Tests & CI
packages/core/solidity/src/account.test.ts, packages/core/solidity/src/zip-foundry.test.ts, packages/core/solidity/src/zip-hardhat.test.ts, .github/workflows/test.yml
Parameterizes account tests over signer/upgradeable variants, adds Account snapshot tests, and extends test discovery to include **/test.ts.
Package pin / snapshots updates
packages/core/solidity/package.json, packages/core/solidity/src/stablecoin.test.ts.md
Updates community-contracts git commit pin and snapshot commit annotations.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as UI (AccountControls)
  participant MCP as MCP Tool
  participant Gen as Account Builder
  participant Upg as setUpgradeableAccount
  participant Print as Printer
  participant Zip as Zip Generator

  UI->>MCP: opts { signer, upgradeable, ... }
  MCP->>Gen: buildAccount(opts)
  Gen->>Upg: setUpgradeableAccount(c, opts.upgradeable)
  alt upgradeable == false
    Gen->>Gen: wire non-upgradeable imports/paths\nattach signer via constructor args
  else upgradeable in {'uups','transparent'}
    Gen->>Gen: set flags (install upgradeable, plugins, transpile)\nadd initialize(...) and initializer wiring\nadapt base names/overrides to *Upgradeable
  end
  Gen->>Print: emit constructor or initialize (shouldUseInitializers)
  Gen-->>Zip: contract c with flags
  alt shouldUseUpgradesPluginsForProxyDeployment
    Zip->>Zip: generate plugin-based proxy deployment
  else
    Zip->>Zip: generate direct contract deployment
  end
Loading
sequenceDiagram
  autonumber
  participant Gen as Account Builder
  participant S as addSigner
  participant OZ as OpenZeppelin Contracts 5.4.0

  Gen->>S: addSigner(c, signer, upgradeable)
  alt signer == ERC7702 and upgradeable != false
    S-->>Gen: throw OptionsError (upgradeable not supported)
  else signer in {ECDSA,P256,RSA}
    S->>OZ: reference SignerX.sol (contracts path)
    S-->>Gen: attach constructor args from signerArgs
  else signer in {MultiSigner, MultiSignerWeighted}
    alt upgradeable != false
      S->>OZ: derive *Upgradeable path (contracts-upgradeable)\nadd initializer and locking constructor
    else
      S->>OZ: use non-upgradeable path and constructor args
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Assessment against linked issues

Objective Addressed Explanation
Use Account and signers from Contracts 5.4.0 instead of Community Contracts (#618)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Account-specific _authorizeUpgrade wiring and plugin gating (packages/core/solidity/src/set-upgradeable.ts) Adds account-specific authorization modifier and plugin/transpile gating beyond a pure import/path replacement.
UI per-signer upgrade gating (packages/ui/src/solidity/AccountControls.svelte, packages/ui/src/solidity/UpgradeabilitySection.svelte) Adds disabled/disabledReason props and ERC7702-specific UI disable logic not strictly necessary for import migration.
Zip generator plugin orchestration (packages/core/solidity/src/zip-foundry.ts, packages/core/solidity/src/zip-hardhat.ts) Introduces flags to control installing upgradeable contracts and employing Upgrades plugins — operational behavior additions beyond switching imports.

Possibly related PRs

Suggested reviewers

  • ernestognw

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5b1bd5a and 4375257.

⛔ Files ignored due to path filters (1)
  • packages/core/solidity/src/account.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (1)
  • .changeset/kind-poems-pull.md (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .changeset/kind-poems-pull.md
⏰ 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). (3)
  • GitHub Check: boostsecurity - boostsecurityio/semgrep-pro
  • GitHub Check: build (solidity, default)
  • GitHub Check: semgrep-cloud-platform/scan
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/release-5.4

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

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

@ernestognw ernestognw marked this pull request as ready for review August 15, 2025 22:35
@ernestognw ernestognw requested review from a team as code owners August 15, 2025 22:35
Copy link

User description

TODO

  • Upgradeability for draft-AccountERC7579
  • Upgradeability for signers

PR Type

Enhancement


Description

  • Migrate account contracts from community to vanilla contracts

  • Add upgradeability support for account signers

  • Update import paths and contract references

  • Enable constructor-based initialization for signers


Diagram Walkthrough

flowchart LR
  A["Community Contracts"] -- "migrate" --> B["Vanilla Contracts 5.4.0"]
  C["Non-upgradeable Signers"] -- "add support" --> D["Upgradeable Signers"]
  E["Initializer Pattern"] -- "replace with" --> F["Constructor Pattern"]
  B --> G["Updated Account Generation"]
  D --> G
  F --> G
Loading

File Walkthrough

Relevant files
Enhancement
7 files
account.ts
Migrate imports and add upgradeability support                     
+73/-22 
signer.ts
Refactor signer initialization with upgradeability             
+68/-66 
sources.ts
Update contract generation logic                                                 
+3/-3     
set-upgradeable.ts
Add account upgradeability configuration                                 
+7/-0     
AccountControls.svelte
Update UI with upgradeability and documentation links       
+19/-19 
App.svelte
Remove experimental label from accounts                                   
+3/-3     
UpgradeabilitySection.svelte
Add disabled state support                                                             
+5/-1     
Tests
3 files
account.test.ts
Add upgradeability test coverage                                                 
+92/-66 
zip-foundry.ts
Add account test case                                                                       
+1/-0     
zip-hardhat.ts
Add account test case                                                                       
+1/-0     
Configuration changes
2 files
solidity.ts
Add upgradeability to AI function parameters                         
+1/-6     
schemas.ts
Add upgradeability to account schema                                         
+1/-0     
Documentation
4 files
sour-hats-grow.md
Document breaking change for contract migration                   
+6/-0     
sad-nails-smash.md
Document upgradeability feature addition                                 
+6/-0     
README.md
Remove experimental status from accounts                                 
+1/-1     
odd-ants-hunt.md
Document constructor addition for signers                               
+6/-0     
Additional files
1 files
account.test.ts.md +7728/-873

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

🧹 Nitpick comments (1)
packages/core/solidity/package.json (1)

25-25: Keep and explicitly pin @openzeppelin/community-contracts in devDependencies

After verification, @openzeppelin/community-contracts is indeed required by several parts of the core/solidity package (stablecoin fixtures, the prepare script, import‐library utilities, and associated tests). To ensure reproducible installs and clear auditability, please update the devDependency to pin a full 40-character commit hash or an official release tag rather than the current 7-character short SHA.

Locations to update:

  • packages/core/solidity/package.json (devDependencies entry)

Proposed diff:

-    "@openzeppelin/community-contracts": "git+https://github.com/OpenZeppelin/openzeppelin-community-contracts.git#2d607bd",
+    "@openzeppelin/community-contracts": "git+https://github.com/OpenZeppelin/openzeppelin-community-contracts.git#<full-40-char-commit-or-tag>"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b9d3740 and 7656f32.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (1)
  • packages/core/solidity/package.json (1 hunks)
⏰ 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). (10)
  • GitHub Check: boostsecurity - boostsecurityio/semgrep-pro
  • GitHub Check: build (stellar, compile)
  • GitHub Check: build (stellar, default)
  • GitHub Check: build (stylus, default)
  • GitHub Check: build (cairo, default)
  • GitHub Check: build (solidity, default)
  • GitHub Check: mcp
  • GitHub Check: format-lint
  • GitHub Check: deno-check
  • GitHub Check: check

@ericglau
Copy link
Member

@coderabbitai The @openzeppelin/community-contracts devDependency intentionally points to a 7 char git commit, so that it can be extracted for display in the UI as the compatible version. The commit hash is validated when running yarn install.

Copy link
Contributor

coderabbitai bot commented Aug 21, 2025

Tip

For best results, initiate chat on the files or code changes.

@ericglau Thank you for the clarification! I understand now that the @openzeppelin/community-contracts devDependency update from commit de17c8e to 2d607bd is intentional. The 7-character git commit format allows the UI to extract and display the compatible version, and the commit hash validation during yarn install ensures integrity. This architectural pattern makes sense for maintaining version compatibility display in the wizard UI.


🧠 Learnings used
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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.

Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.

Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.

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.

@ernestognw
Copy link
Member Author

@ernestognw Can you please review a few changes that I made:

Amazing, thanks @ericglau, sure.

  • Changed UUPSUpgradeable to come from contracts-upgradeable

Yeah, good catch. I see we're consistently using it like that in all other upgradeable variants so looks good to me.

  • Changed the constructor comment for Account/signers to use /// @custom:oz-upgrades-unsafe-allow-reachable constructor (currently it behaves the same as without "reachable", but when OpenZeppelin/openzeppelin-upgrades#1184 is fixed in the Upgrades Plugins, it will allow EIP712 to pass validations.)

Got it. Also all good here.

Also, the following are also coming from vanilla contracts even though there are upgradeable variants. It looks fine to me as I don't see any storage usage, but please confirm if this is intentional:

  • ERC1155Holder
  • ERC721Holder

Also great catch. So these 2 contracts are stateless (no storage variables) so it's safe to use either. I think we should've marked this as @custom:stateless in vanilla but never did. I think it caused some CI issues at the time.

Comment on lines 679 to 712
contract MyAccount is Initializable, Account, EIP712, ERC7739, AccountERC7579Upgradeable, UUPSUpgradeable {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() EIP712("MyAccount", "1") {␊
_disableInitializers();␊
}␊
function isValidSignature(bytes32 hash, bytes calldata signature)␊
public␊
view␊
override(AccountERC7579Upgradeable, ERC7739)␊
returns (bytes4)␊
{␊
// ERC-7739 can return the ERC-1271 magic value, 0xffffffff (invalid) or 0x77390001 (detection).␊
// If the returned value is 0xffffffff, fallback to ERC-7579 validation.␊
bytes4 erc7739magic = ERC7739.isValidSignature(hash, signature);␊
return erc7739magic == bytes4(0xffffffff) ? AccountERC7579Upgradeable.isValidSignature(hash, signature) : erc7739magic;␊
}␊
function _authorizeUpgrade(address newImplementation)␊
internal␊
override␊
onlyEntryPointOrSelf␊
{}␊
// The following functions are overrides required by Solidity.␊
function _validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)␊
internal␊
override(Account, AccountERC7579Upgradeable)␊
returns (uint256)␊
{␊
return super._validateUserOp(userOp, userOpHash);␊
}␊
}␊
Copy link
Contributor

Choose a reason for hiding this comment

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

This accoutn needs an initializer that installs a first module. Otherwise, its just bricked at construction.
This is particularly visible in this case, but I believe its all upgradeable accounts that are missing an initializer. In most cases the initializer would be empty, so we don't really care, but in cases where the initializer is actually needed that is more serious.

Copy link
Contributor

Choose a reason for hiding this comment

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

Note: we have the same issue with the non-upgradeable version. If we don't have a signer, and just use 7579, the constructor doesn't install any "initial module"

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

🧹 Nitpick comments (2)
packages/core/solidity/src/signer.ts (2)

33-49: Upgradeable path is correctly wired; ensure deps get installed

  • Initializable + locking constructor + initializer + Upgradeable parent are correctly applied.
  • Minor: confirm the generator ensures @openzeppelin/contracts-upgradeable is installed in zip scenarios when this path is hit (either via import scanning or by toggling a flag). If needed, set c.shouldInstallContractsUpgradeable = true here.

If you rely on a flag, minimally:

       c.addParent({
         name: 'Initializable',
         path: '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol',
       });
+      c.shouldInstallContractsUpgradeable = true;

62-77: Placement of the “unsafe-allow-reachable constructor” tag — add a contract-level tag for robustness

The constructor-body doc comment may be missed by some tooling. Consider also emitting a contract-level natspec tag to be extra safe.

Apply in addLockingConstructorAllowReachable:

 export function addLockingConstructorAllowReachable(c: ContractBuilder, bodyComments?: string[]): void {
   const disableInitializers = '_disableInitializers();';

   if (!c.constructorCode.includes(disableInitializers)) {
-    c.addConstructorComment('/// @custom:oz-upgrades-unsafe-allow-reachable constructor');
+    c.addConstructorComment('/// @custom:oz-upgrades-unsafe-allow-reachable constructor');
+    c.addNatspecTag('@custom:oz-upgrades-unsafe-allow-reachable', 'constructor');
     bodyComments?.forEach(comment => c.addConstructorCode(comment));
     c.addConstructorCode(disableInitializers);
   }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c8e260d and a44081a.

⛔ Files ignored due to path filters (1)
  • packages/core/solidity/src/account.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • packages/core/solidity/src/account.ts (9 hunks)
  • packages/core/solidity/src/signer.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
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.
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
📚 Learning: 2025-08-19T01:15:58.945Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/src/signer.ts
  • packages/core/solidity/src/account.ts
📚 Learning: 2025-08-19T01:15:58.945Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/src/signer.ts
  • packages/core/solidity/src/account.ts
📚 Learning: 2025-08-15T23:23:13.097Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/signer.ts
  • packages/core/solidity/src/account.ts
📚 Learning: 2025-08-15T22:52:34.129Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/signer.ts
  • packages/core/solidity/src/account.ts
📚 Learning: 2025-08-20T20:23:30.259Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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/signer.ts
  • packages/core/solidity/src/account.ts
📚 Learning: 2025-08-21T19:44:06.797Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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/src/signer.ts
  • packages/core/solidity/src/account.ts
📚 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:

  • packages/core/solidity/src/signer.ts
  • packages/core/solidity/src/account.ts
🧬 Code graph analysis (2)
packages/core/solidity/src/signer.ts (2)
packages/core/solidity/src/contract.ts (1)
  • ContractBuilder (78-238)
packages/core/solidity/src/set-upgradeable.ts (1)
  • Upgradeable (8-8)
packages/core/solidity/src/account.ts (3)
packages/core/solidity/src/set-upgradeable.ts (1)
  • setUpgradeableAccount (64-78)
packages/core/solidity/src/signer.ts (5)
  • addSigner (9-60)
  • addLockingConstructorAllowReachable (69-77)
  • signerArgs (106-125)
  • signerFunctions (127-137)
  • signers (79-104)
packages/core/solidity/src/contract.ts (2)
  • functions (119-121)
  • ContractBuilder (78-238)
⏰ 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). (4)
  • GitHub Check: boostsecurity - boostsecurityio/semgrep-pro
  • GitHub Check: build (stellar, compile)
  • GitHub Check: build (solidity, default)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (19)
packages/core/solidity/src/signer.ts (7)

9-9: Signature update to addSigner looks good

Adding the upgradeable parameter is consistent with the PR goals and enables clean branching.


20-27: Good guard: block ERC7702 when upgradeable is true

Clear error message, aligned with “EOAs can upgrade by redelegation.”


41-42: Initializer modifier present — good catch

The initializer modifier prevents re-initialization; this addresses the earlier risk.


50-55: Non-upgradeable constructor flow is correct

Passing constructor args through to the parent is the right approach for vanilla signers.


79-104: Signer import map updated to vanilla Contracts — correct paths

Paths point to the new contracts/utils/cryptography/signers locations introduced in 5.4.0.


106-125: Signer args match 5.4.0 APIs (types/ordering)

  • ECDSA: address
  • P256: qx, qy as bytes32
  • RSA: e, n as bytes
  • Multisig: bytes[] signers + uint64 threshold
  • MultisigWeighted: bytes[] signers + uint64[] weights + uint64 threshold

These align with OZ 5.4.0.


12-16: Override base is correct
I verified in the OZ 5.4.0 upgradeable sources that _rawSignatureValidation is declared only in MultiSignerERC7913Upgradeable (at line 237) and not re-declared in MultiSignerERC7913WeightedUpgradeable. The current override using signers.Multisig.name covers the sole declaration and will not cause any “does not override anything” errors. No changes needed.

packages/core/solidity/src/account.ts (12)

7-15: LGTM - Clean import structure for signer functionality.

The imports from ./signer are well-organized and provide all necessary signer-related functionality including types, utilities, and the main addSigner function. The addition of addLockingConstructorAllowReachable aligns with the upgradeable account patterns.


70-70: Excellent integration of upgradeable account setup.

The call to setUpgradeableAccount properly integrates the upgradeability configuration from the common options. This follows the established pattern from other contract types and ensures consistency across the codebase.


87-87: Successful migration to vanilla OpenZeppelin contracts.

The base Account import has been correctly migrated from community contracts to the standard @openzeppelin/contracts/account/Account.sol path. This aligns with the PR objectives to use OpenZeppelin Contracts 5.4.0 instead of community contracts.


96-97: Proper signer integration with upgradeability support.

The addSigner call now correctly passes the upgradeable flag, and the subsequent addSignerInitializer call handles the initialization logic. This design properly separates concerns between signer setup and initialization patterns.


163-166: Well-implemented dynamic naming for upgradeable variants.

The conditional naming logic correctly handles both upgradeable and non-upgradeable variants:

  • baseERC7579AccountName: AccountERC7579 vs AccountERC7579Upgradeable
  • fullERC7579AccountName: Includes the specific module type with Upgradeable suffix
  • packageName: Correctly switches between contracts and contracts-upgradeable

This follows the established pattern and addresses the objective to support both deployment modes.


178-203: Robust initialization pattern for ERC7579 without signers.

The logic properly handles the requirement that ERC7579 accounts without signers must have at least one module. The conditional branching between upgradeable and non-upgradeable flows is correct:

  • Upgradeable: Uses initializer pattern with Initializable and addLockingConstructorAllowReachable
  • Non-upgradeable: Uses constructor arguments and constructor code

The validation requiring either validator or executor module types is appropriate for ERC7579 compliance.


205-222: Sophisticated signature validation override logic.

The isValidSignature override handling is well-designed:

  1. Correctly overrides the base ERC7579 account
  2. For ERC7739: Implements fallback logic where ERC7739 returning 0xffffffff falls back to ERC7579 validation
  3. Dynamic naming ensures the correct base contract is referenced

The comment explaining the ERC7739 magic values (0xffffffff for invalid, 0x77390001 for detection) is helpful for maintainability.


224-267: Well-architected initializer pattern for non-upgradeable accounts.

The addSignerInitializer function properly implements the ERC-4337 deployment pattern where accounts are deployed as clones by factories. Key strengths:

  1. Correct architectural understanding: Uses initializers even for non-upgradeable accounts because ERC-4337 accounts are deployed as minimal clone proxies
  2. Proper Initializable import: Conditionally imports from the correct package (contracts vs contracts-upgradeable)
  3. Good constructor comments: Explains why initializers are disabled for the implementation
  4. Complete signer initialization: Handles all signer types with appropriate initialization calls

The early returns for upgradeable accounts (handled in signer.ts) and ERC7702 (no initialization needed) are appropriate.


315-343: Complex but correct signature validation disambiguation.

The logic for handling conflicts between Signer and AccountERC7579 implementations is sophisticated:

  1. Dynamic naming: Correctly constructs upgradeable variant names
  2. Import management: Properly imports AbstractSigner for override resolution
  3. Inheritance guidance: Provides clear comments about inheritance order requirements
  4. MultisigWeighted handling: Correctly imports the base Multisig contract with dynamic path resolution

The comment about ensuring correct inheritance order is crucial for proper function resolution in Solidity's C3 linearization.


385-392: Correct type updates for threshold and weights.

The function signatures have been updated to use uint64 for threshold and weight parameters, which aligns with the OpenZeppelin Contracts 5.4.0 signer implementations. This type change is more gas-efficient than uint256 for these use cases.


151-151: The next step is to confirm which OpenZeppelin Contracts version you’re targeting so we can verify that the path exists in that release. I’ve added a script to extract the installed version from your package.json—once we have that, we can check GitHub for the corresponding file.


109-109: Ensure draft-ERC7739.sol is present in your OpenZeppelin package

It looks like searching your codebase for “ERC7739” only turned up references in your tests and schema definitions, but didn’t confirm that the actual Solidity file exists in the installed OpenZeppelin Contracts. You should:

  • Verify that your project’s installed version of @openzeppelin/contracts (in package.json) includes utils/cryptography/signers/draft-ERC7739.sol.
  • If it isn’t present, either upgrade to an OpenZeppelin release that ships this draft or adjust the import to point at the correct path.
  • Double-check your node_modules or the tarball of @openzeppelin/contracts to ensure the file name and directory structure match exactly.

Please confirm that the import path

path: '@openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol',

actually resolves to a file in your dependencies.

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

🧹 Nitpick comments (3)
packages/core/solidity/src/helpers.ts (2)

1-1: Use POSIX path utils to avoid backslashes in Solidity imports

Node’s default path API is OS-dependent and can emit backslashes on Windows. Use path.posix to guarantee forward slashes in import specifiers.

Apply:

-import path from "path";
+import { posix as path } from "node:path";

20-21: Make the contracts segment replacement more robust

If '/contracts/' isn’t present, the replacement is a no-op; that’s fine. Consider being explicit to avoid accidental matches in other segments.

Example:

-                dir: dir.replace('/contracts/', '/contracts-upgradeable/'),
+                dir: dir.includes('/contracts/') ? dir.replace('/contracts/', '/contracts-upgradeable/') : dir,
packages/core/solidity/src/account.ts (1)

233-239: Remove unreachable ternary for Initializable import

This branch only executes when opts.upgradeable is false (early return above), so the ternary’s true side is unreachable. Simplify.

Apply:

-    path: opts.upgradeable
-      ? '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'
-      : '@openzeppelin/contracts/proxy/utils/Initializable.sol',
+    path: '@openzeppelin/contracts/proxy/utils/Initializable.sol',
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a44081a and 64af729.

📒 Files selected for processing (3)
  • packages/core/solidity/src/account.ts (9 hunks)
  • packages/core/solidity/src/helpers.ts (1 hunks)
  • packages/core/solidity/src/signer.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
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.
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
📚 Learning: 2025-08-21T19:44:06.797Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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/src/helpers.ts
  • packages/core/solidity/src/account.ts
  • packages/core/solidity/src/signer.ts
📚 Learning: 2025-08-15T23:23:13.097Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/account.ts
  • packages/core/solidity/src/signer.ts
📚 Learning: 2025-08-20T20:23:30.259Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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/account.ts
  • packages/core/solidity/src/signer.ts
📚 Learning: 2025-08-19T01:15:58.945Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/src/account.ts
  • packages/core/solidity/src/signer.ts
📚 Learning: 2025-08-19T01:15:58.945Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/src/account.ts
  • packages/core/solidity/src/signer.ts
📚 Learning: 2025-08-15T22:52:34.129Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/account.ts
  • packages/core/solidity/src/signer.ts
📚 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:

  • packages/core/solidity/src/account.ts
  • packages/core/solidity/src/signer.ts
🧬 Code graph analysis (2)
packages/core/solidity/src/account.ts (4)
packages/core/solidity/src/set-upgradeable.ts (1)
  • setUpgradeableAccount (64-78)
packages/core/solidity/src/signer.ts (5)
  • addSigner (10-59)
  • addLockingConstructorAllowReachable (68-76)
  • signerArgs (105-124)
  • signerFunctions (126-136)
  • signers (78-103)
packages/core/solidity/src/helpers.ts (1)
  • makeUpgradeable (12-25)
packages/core/solidity/src/contract.ts (2)
  • functions (119-121)
  • ContractBuilder (78-238)
packages/core/solidity/src/signer.ts (3)
packages/core/solidity/src/contract.ts (1)
  • ContractBuilder (78-238)
packages/core/solidity/src/set-upgradeable.ts (1)
  • Upgradeable (8-8)
packages/core/solidity/src/helpers.ts (1)
  • makeUpgradeable (12-25)
🪛 Biome (2.1.2)
packages/core/solidity/src/helpers.ts

[error] 18-18: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🪛 GitHub Actions: Test
packages/core/solidity/src/helpers.ts

[warning] 1-1: Prettier formatting issue detected in this file. Run 'prettier --write' to fix.

packages/core/solidity/src/account.ts

[warning] 1-1: Prettier formatting issue detected in this file. Run 'prettier --write' to fix.

packages/core/solidity/src/signer.ts

[warning] 1-1: Prettier formatting issue detected in this file. Run 'prettier --write' to fix.

⏰ 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: boostsecurity - boostsecurityio/semgrep-pro
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (11)
packages/core/solidity/src/helpers.ts (1)

1-25: Formatting: run Prettier

CI flagged a Prettier issue. Please run: prettier --write packages/core/solidity/src/helpers.ts

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

164-176: Dynamic ERC-7579 base selection looks correct

makeUpgradeable is applied consistently to both names and paths for AccountERC7579 and Hooked variants. This aligns with OZ 5.4 layout.


205-218: isValidSignature fallback logic is sound

ERC-7739 fallback to ERC-7579 on 0xffffffff is correctly implemented, and overrides reference the upgradeability-adjusted base name.


315-340: Good disambiguation for _rawSignatureValidation with MultisigWeighted

Importing MultiSigner (base of Weighted) for override disambiguation is appropriate. No action needed.


71-71: Upgradeability wiring is placed correctly

setUpgradeableAccount is invoked before imports/overrides that depend on upgradeable state. Good sequencing.


1-394: Formatting: run Prettier

CI flagged a Prettier issue. Please run: prettier --write packages/core/solidity/src/account.ts

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

35-47: Upgradeable signer path and initializer setup LGTM

Uses Initializable, locks constructor, adds initializer, and imports the correct Upgradeable signer via makeUpgradeable.


49-54: Non-upgradeable constructor flow LGTM

Constructor args are forwarded to vanilla signer parents; aligns with OZ 5.4 constructors.


13-17: Override target name selection is correct for Weighted multisig

Targeting MultiSigner for the override (and applying makeUpgradeable) matches the inheritance (Weighted extends MultiSigner).


68-76: Idempotent locking constructor helper is well-factored

addLockingConstructorAllowReachable avoids duplicate inserts and adds the correct validation tag.


1-137: Formatting: run Prettier

CI flagged a Prettier issue. Please run: prettier --write packages/core/solidity/src/signer.ts

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

♻️ Duplicate comments (1)
packages/core/solidity/src/signer.ts (1)

46-51: Good: no constructor args in upgradeable branch; args only for non-upgradeable

This implements the proxy-safe pattern and resolves the earlier concern about constructors in upgradeable flows.

🧹 Nitpick comments (3)
packages/core/solidity/src/signer.ts (3)

16-24: Reorder: throw before mutating the builder in the ERC7702 path

Avoid partial mutations if an error is thrown by moving the parent addition after the error check.

       case 'ERC7702':
-      c.addParent(signers[signer]);
-      if (upgradeable) {
+      if (upgradeable) {
         throw new OptionsError({
           erc7702: 'EOAs can upgrade by redelegating to a new account',
           upgradeable: 'EOAs can upgrade by redelegating to a new account',
         });
-      }
+      }
+      c.addParent(signers[signer]);
       break;

41-44: Use makeUpgradeable for the name too (minor consistency)

Keeps name/path transformation in sync and avoids manual template strings.

-        c.addParent({
-          name: `${signers[signer].name}Upgradeable`,
+        c.addParent({
+          name: makeUpgradeable(signers[signer].name, upgradeable),
           path: makeUpgradeable(signers[signer].path, upgradeable),
         });

65-72: Guard constructor comment when auto-transpiling is enabled

addConstructorComment throws if shouldAutoTranspileImports is true. Skip the comment in that case to avoid generation failures while still locking initializers.

 export function addLockingConstructorAllowReachable(c: ContractBuilder, bodyComments?: string[]): void {
   const disableInitializers = '_disableInitializers();';
 
   if (!c.constructorCode.includes(disableInitializers)) {
-    c.addConstructorComment('/// @custom:oz-upgrades-unsafe-allow-reachable constructor');
+    if (!c.shouldAutoTranspileImports) {
+      c.addConstructorComment('/// @custom:oz-upgrades-unsafe-allow-reachable constructor');
+    }
     bodyComments?.forEach(comment => c.addConstructorCode(comment));
     c.addConstructorCode(disableInitializers);
   }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 64af729 and bbba3ad.

📒 Files selected for processing (3)
  • packages/core/solidity/src/account.ts (9 hunks)
  • packages/core/solidity/src/helpers.ts (1 hunks)
  • packages/core/solidity/src/signer.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/solidity/src/helpers.ts
  • packages/core/solidity/src/account.ts
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
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.
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
📚 Learning: 2025-08-19T01:15:58.945Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/src/signer.ts
📚 Learning: 2025-08-19T01:15:58.945Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/src/signer.ts
📚 Learning: 2025-08-15T23:23:13.097Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/signer.ts
📚 Learning: 2025-08-15T22:52:34.129Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/signer.ts
📚 Learning: 2025-08-20T20:23:30.259Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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/signer.ts
📚 Learning: 2025-08-21T19:44:06.797Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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/src/signer.ts
📚 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:

  • packages/core/solidity/src/signer.ts
🧬 Code graph analysis (1)
packages/core/solidity/src/signer.ts (4)
packages/core/solidity/src/contract.ts (1)
  • ContractBuilder (78-238)
packages/core/solidity/src/index.ts (3)
  • ContractBuilder (5-5)
  • Upgradeable (10-10)
  • OptionsError (17-17)
packages/core/solidity/src/set-upgradeable.ts (1)
  • Upgradeable (8-8)
packages/core/solidity/src/helpers.ts (1)
  • makeUpgradeable (12-26)
⏰ 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). (4)
  • GitHub Check: boostsecurity - boostsecurityio/semgrep-pro
  • GitHub Check: build (stellar, compile)
  • GitHub Check: build (solidity, default)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (3)
packages/core/solidity/src/signer.ts (3)

13-15: Override target for Weighted multisig is correct

Using MultiSignerERC7913 as the override base when the selected signer is MultisigWeighted is appropriate: MultiSignerERC7913Weighted extends MultiSignerERC7913 and does not re-declare the low-level _rawSignatureValidation; the override should reference the base that defines it. (docs.openzeppelin.com)


31-45: Upgradeable wiring looks solid (constructor lock + initializer)

  • Initializable parent import is correct.
  • Locking constructor via _disableInitializers plus oz-upgrades-unsafe-allow-reachable annotation matches recommended upgrades validations.
  • initialize calls the correct __X_init with the right arg order for each signer.

102-121: Arg shapes and types align with OZ 5.4 signers

  • ECDSA(address), P256(bytes32,bytes32), RSA(bytes,bytes), Multisig(bytes[],uint64), Weighted(bytes[],uint64[],uint64) match the 5.4 APIs. (github.com)

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

♻️ Duplicate comments (1)
packages/core/solidity/src/helpers.ts (1)

17-24: Ack: prior linter warning about declarations in switch cases is addressed
Cases are wrapped in a block and a default branch exists, resolving the earlier Biome warning.

🧹 Nitpick comments (2)
packages/core/solidity/src/helpers.ts (2)

25-28: Include the unknown option value in the error for easier debugging

Apply:

-      throw new Error('Unknown upgradeable option');
+      throw new Error(`Unknown upgradeable option: ${String(upgradeable)}`);

4-11: Tighten wording in docs: be explicit about accepted values

Apply:

-// If upgradeable is true-ish, translate a contract name or contract path into its corresponding upgradeable variant.
+// If upgradeable is 'uups' or 'transparent', translate a contract name or contract path into its corresponding upgradeable variant.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bbba3ad and 102afdf.

📒 Files selected for processing (1)
  • packages/core/solidity/src/helpers.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
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.
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
📚 Learning: 2025-08-21T19:44:06.797Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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/src/helpers.ts
📚 Learning: 2025-08-20T20:23:30.259Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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/helpers.ts
⏰ 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). (4)
  • GitHub Check: boostsecurity - boostsecurityio/semgrep-pro
  • GitHub Check: build (stellar, compile)
  • GitHub Check: build (solidity, default)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/core/solidity/src/helpers.ts (1)

12-29: LGTM: exhaustive switch + never guard is solid
The const _: never = upgradeable makes this future-proof at compile time. Nice.

@ericglau ericglau requested a review from Amxx August 27, 2025 15:57
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: 0

🧹 Nitpick comments (2)
packages/core/solidity/src/signer.ts (2)

31-45: Set contracts-upgradeable install flag to avoid missing dependency in zips

You import from @openzeppelin/contracts-upgradeable here but don’t mark the builder to install it. In other flows this is often set centrally; since you’re bypassing the helper, set it locally to be safe.

Apply this diff inside the if (upgradeable) branch:

       if (upgradeable) {
+        // Ensure consumers install @openzeppelin/contracts-upgradeable
+        c.shouldInstallContractsUpgradeable = true;
         c.addParent({
           name: 'Initializable',
           path: '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol',
         });

67-74: Make duplicate-lock detection more robust

The guard checks for the exact string _disableInitializers();. Minor variations (whitespace/comments) could bypass it. Consider tracking a boolean or checking via regex.

-  const disableInitializers = '_disableInitializers();';
-  if (!c.constructorCode.includes(disableInitializers)) {
+  const disableInitializers = /_disableInitializers\(\)\s*;/;
+  if (!c.constructorCode.some(l => disableInitializers.test(l))) {
     c.addConstructorComment('/// @custom:oz-upgrades-unsafe-allow-reachable constructor');
     bodyComments?.forEach(comment => c.addConstructorCode(comment));
-    c.addConstructorCode(disableInitializers);
+    c.addConstructorCode('_disableInitializers();');
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 102afdf and e3f45b2.

📒 Files selected for processing (1)
  • packages/core/solidity/src/signer.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
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.
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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.
📚 Learning: 2025-08-19T01:15:58.945Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/src/signer.ts
📚 Learning: 2025-08-19T01:15:58.945Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/src/signer.ts
📚 Learning: 2025-08-15T23:23:13.097Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/signer.ts
📚 Learning: 2025-08-15T22:52:34.129Z
Learnt from: ernestognw
PR: OpenZeppelin/contracts-wizard#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/signer.ts
📚 Learning: 2025-08-20T20:23:30.259Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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/signer.ts
📚 Learning: 2025-08-21T19:44:06.797Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#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/src/signer.ts
📚 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:

  • packages/core/solidity/src/signer.ts
🧬 Code graph analysis (1)
packages/core/solidity/src/signer.ts (3)
packages/core/solidity/src/contract.ts (1)
  • ContractBuilder (78-238)
packages/core/solidity/src/set-upgradeable.ts (1)
  • Upgradeable (8-8)
packages/core/solidity/src/helpers.ts (1)
  • makeUpgradeable (12-30)
⏰ 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). (4)
  • GitHub Check: boostsecurity - boostsecurityio/semgrep-pro
  • GitHub Check: build (stellar, compile)
  • GitHub Check: build (solidity, default)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (5)
packages/core/solidity/src/signer.ts (5)

13-15: Override target for MultisigWeighted looks correct

Using the base MultiSignerERC7913 for the override when the selected signer is MultisigWeighted matches the inheritance in OZ 5.4.0. LGTM.


17-25: Blocking ERC7702 + upgradeable is correct

Throwing OptionsError when upgradeable is set with ERC7702 is the right constraint. LGTM.


77-103: Signer import migration to vanilla paths is correct

Paths point to OZ Contracts 5.4.0 signers. LGTM.


104-123: Constructor/initializer arg shapes match OZ 5.4.0

Arg names and types align with signer constructors/init functions (ECDSA, P256, RSA, Multisig, Weighted). LGTM.


38-41: No duplicate initializer in any single contract

Our search across packages/core/solidity/src found three initialize modifiers: one in signer.ts (line 38) and two in account.ts (lines 199 and 248)【scriptOutput】. However, the two in account.ts are guarded by an if/else and thus only one initializer is ever emitted per build, and signer.ts generates a separate contract entirely. There is no scenario where more than one initialize modifier ends up in the same contract, so no change is required here.

Likely an incorrect or invalid review comment.

@ericglau
Copy link
Member

@SocketSecurity ignore npm/[email protected]
@SocketSecurity ignore npm/[email protected]
@SocketSecurity ignore npm/[email protected]
Looks like false positives, and not related to this PR.

@ericglau
Copy link
Member

@SocketSecurity ignore npm/[email protected]

@ericglau ericglau enabled auto-merge (squash) August 28, 2025 14:23
@ericglau ericglau merged commit 41d5c74 into master Aug 28, 2025
23 checks passed
@ericglau ericglau deleted the chore/release-5.4 branch August 28, 2025 14:23
@github-actions github-actions bot locked and limited conversation to collaborators Aug 28, 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.

Use Account and signers from Contracts 5.4.0 instead of Community Contracts
3 participants