Skip to content

Conversation

ericglau
Copy link
Member

@ericglau ericglau commented Sep 25, 2025

  • Adds the Download Hardhat package option for Polkadot, limited to non-upgradeable contracts for now. This extends from Solidity Wizard's Download Hardhat functionality.
  • Changes required Node version to 22, since this is a requirement of the Hardhat Polkadot plugin.

Remaining issues (may be out of scope of Wizard):

  • npx hardhat compile fails with the following error, even though compiler version is set to 0.8.27. However, running npx hardhat compile a second time causes compilation to succeed.
Error: ParserError: Source file requires different compiler version (current compiler is 0.8.26+commit.8a97fa7a.Emscripten.clang) - note that nightly builds are considered to be strictly less than the released version
 --> contracts/MyToken.sol:3:1:
  |
3 | pragma solidity ^0.8.27;
  | ^^^^^^^^^^^^^^^^^^^^^^^^

Note for code review:

  • Commit 8145433 is cherry-picked from a not-yet-merged PR, which adds extensibility to the zip-hardhat.ts file.
  • Only commit 9e22ed5 (and later, if any) is specific for this PR.

@ericglau ericglau requested a review from KitHat September 25, 2025 22:26
@ericglau ericglau requested review from a team as code owners September 25, 2025 22:26
Copy link
Contributor

coderabbitai bot commented Sep 25, 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

Bumps Node.js to 22 and setup-node to v5 in CI. Refactors Hardhat zip generation into a class. Adds a Polkadot-specific Hardhat zip generator, exports, and tests with snapshots. Updates UI overrides to function-based omit and optional override for Hardhat zip, with dynamic import in Polkadot UI.

Changes

Cohort / File(s) Summary
CI and Node version bump
.github/actions/setup/action.yml, .nvmrc
Update actions/setup-node to v5 and Node.js version from 20 to 22; no flow changes.
Hardhat zip generator refactor
packages/core/solidity/src/zip-hardhat.ts, packages/core/solidity/src/zip-hardhat.test.ts.md
Introduce HardhatZipGenerator class, restructure content generation methods, delegate zipHardhat to the class; update snapshots for changed templates/comments and unsafeAllow array syntax.
Polkadot Hardhat zip support
packages/core/solidity/src/zip-hardhat-polkadot.ts, packages/core/solidity/zip-env-hardhat-polkadot.ts, packages/core/solidity/zip-env-hardhat-polkadot.js, packages/core/solidity/src/environments/hardhat/polkadot/package.json, packages/core/solidity/src/zip-hardhat-polkadot.test.ts, packages/core/solidity/src/zip-hardhat-polkadot.test.ts.md
Add Polkadot-specific generator extending Hardhat setup, re-export/build proxies, environment package.json, end-to-end AVA test with layout/assertions, and snapshot report.
UI overrides and dynamic generation
packages/ui/src/solidity/overrides.ts, packages/ui/src/solidity/App.svelte, packages/ui/src/polkadot/App.svelte
Change omitZipHardhat from boolean to function; add optional overrideZipHardhat. Update App.svelte to call function-based omit and delegate to override when provided; Polkadot UI dynamically imports zip-env-hardhat-polkadot and routes generation.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User
  participant UI as Solidity App.svelte
  participant Ov as Overrides
  participant Gen as Core Hardhat Generator

  User->>UI: Click "Download Hardhat ZIP"
  UI->>Ov: omitZipHardhat(opts)
  alt omit = true
    UI-->>User: Skip Hardhat ZIP
  else omit = false
    UI->>Ov: overrideZipHardhat?
    alt override present
      UI->>Ov: overrideZipHardhat(contract, opts)
      Ov-->>UI: JSZip
    else no override
      UI->>Gen: zipHardhat(contract, opts)
      Gen-->>UI: JSZip
    end
    UI-->>User: Start ZIP download
  end
Loading
sequenceDiagram
  autonumber
  participant PolyUI as Polkadot App.svelte
  participant Dyn as Dynamic Import
  participant PGen as zipHardhatPolkadot
  participant HGen as HardhatZipGenerator

  PolyUI->>Dyn: import("@openzeppelin/wizard/zip-env-hardhat-polkadot")
  Dyn-->>PolyUI: { zipHardhatPolkadot }
  PolyUI->>PGen: zipHardhatPolkadot(contract, opts)
  PGen->>HGen: Extend Hardhat config (add @parity/hardhat-polkadot)
  HGen-->>PolyUI: JSZip (Polkadot Hardhat project)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • KitHat
  • gonzaotc

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
Description Check ✅ Passed The description directly outlines the added Polkadot download option and the Node version update required for the Hardhat Polkadot plugin, which align perfectly with the implemented changes. It also notes remaining issues and provides context for reviewers, demonstrating clear relevance to the changeset. The content is neither off-topic nor overly generic and offers useful guidance without obscuring the main objectives.
Title Check ✅ Passed The title accurately summarizes the primary change of the pull request by stating that a Hardhat Polkadot zip download option is being added, matching the PR’s main intent to extend the Download Hardhat feature for Polkadot.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

❤️ Share

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

Copy link

socket-security bot commented Sep 25, 2025

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
packages/core/solidity/src/environments/hardhat/polkadot/package.json (1)

11-16: Consider version range strategy for dependencies.

The package uses caret (^) version ranges for all dependencies. While this allows for minor/patch updates, consider whether stricter pinning is appropriate for critical dependencies like the Polkadot plugin.

For more stability, consider exact version pinning for newer/experimental dependencies:

  "devDependencies": {
    "@openzeppelin/contracts": "^5.4.0",
-   "@parity/hardhat-polkadot": "^0.1.9",
+   "@parity/hardhat-polkadot": "0.1.9",
    "@nomicfoundation/hardhat-toolbox": "^6.1.0",
    "hardhat": "^2.16.1"
  }
packages/core/solidity/src/zip-hardhat-polkadot.test.ts (1)

121-123: Consider extracting the duplicate asString helper

This asString function duplicates the one already available in packages/core/stellar/src/utils/zip-test.ts.

Consider importing the shared utility instead:

-async function asString(item: JSZipObject) {
-  return Buffer.from(await item.async('arraybuffer')).toString();
-}
+import { asString } from '../../stellar/src/utils/zip-test';

Or if cross-package imports aren't desired, extract it to a shared test utilities module within the solidity package.

packages/core/solidity/src/zip-hardhat-polkadot.ts (1)

57-62: Extra whitespace in gitignore template

The gitignore template has inconsistent indentation with extra spaces at the beginning and end.

Clean up the formatting:

  protected getGitIgnoreHardhatIgnition(): string {
-    return `
-# Hardhat Ignition default folder for deployments against a local Polkadot Revive Dev node
-ignition/deployments/chain-420420420
-    `;
+    return `
+# Hardhat Ignition default folder for deployments against a local Polkadot Revive Dev node
+ignition/deployments/chain-420420420`;
  }
packages/core/solidity/src/zip-hardhat.ts (1)

64-73: Consider validating constructor argument types

The code assumes that non-address constructor arguments need manual setting, but doesn't validate the actual types. This could be enhanced to provide more specific guidance based on the actual argument types.

Consider providing more specific placeholders based on the argument type:

  private declareVariables(args: FunctionArgument[]): Lines[] {
    const vars = [];
    for (let i = 0; i < args.length; i++) {
      if (args[i]!.type === 'address') {
        vars.push(`const ${args[i]!.name} = (await ethers.getSigners())[${i}].address;`);
      } else {
+       const argType = typeof args[i]!.type === 'string' ? args[i]!.type : 'contract';
+       const placeholder = this.getPlaceholderForType(argType);
        vars.push(`// TODO: Set the following constructor argument`);
-       vars.push(`// const ${args[i]!.name} = ...;`);
+       vars.push(`// const ${args[i]!.name} = ${placeholder};`);
      }
    }
    return vars;
  }
+ 
+ private getPlaceholderForType(type: string): string {
+   switch(type) {
+     case 'uint256': return '1000';
+     case 'string': return '"example"';
+     case 'bool': return 'true';
+     default: return '...';
+   }
+ }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a90806 and 9e22ed5.

⛔ Files ignored due to path filters (3)
  • packages/core/solidity/src/environments/hardhat/polkadot/package-lock.json is excluded by !**/package-lock.json
  • packages/core/solidity/src/zip-hardhat-polkadot.test.ts.snap is excluded by !**/*.snap
  • packages/core/solidity/src/zip-hardhat.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (13)
  • .github/actions/setup/action.yml (1 hunks)
  • .nvmrc (1 hunks)
  • packages/core/solidity/src/environments/hardhat/polkadot/package.json (1 hunks)
  • packages/core/solidity/src/zip-hardhat-polkadot.test.ts (1 hunks)
  • packages/core/solidity/src/zip-hardhat-polkadot.test.ts.md (1 hunks)
  • packages/core/solidity/src/zip-hardhat-polkadot.ts (1 hunks)
  • packages/core/solidity/src/zip-hardhat.test.ts.md (7 hunks)
  • packages/core/solidity/src/zip-hardhat.ts (4 hunks)
  • packages/core/solidity/zip-env-hardhat-polkadot.js (1 hunks)
  • packages/core/solidity/zip-env-hardhat-polkadot.ts (1 hunks)
  • packages/ui/src/polkadot/App.svelte (2 hunks)
  • packages/ui/src/solidity/App.svelte (2 hunks)
  • packages/ui/src/solidity/overrides.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-24T20:55:43.331Z
Learnt from: CoveMB
PR: OpenZeppelin/contracts-wizard#665
File: packages/ui/src/solidity/remix.node.test.ts:0-0
Timestamp: 2025-09-24T20:55:43.331Z
Learning: In the OpenZeppelin contracts-wizard project, the UI package tests use AVA framework which provides browser API polyfills, so `atob` and other browser APIs are available in the test environment.

Applied to files:

  • packages/core/solidity/src/zip-hardhat-polkadot.test.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/zip-hardhat.test.ts.md
📚 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/zip-hardhat.test.ts.md
🧬 Code graph analysis (3)
packages/core/solidity/src/zip-hardhat-polkadot.test.ts (2)
packages/core/solidity/src/zip-hardhat-polkadot.ts (1)
  • zipHardhatPolkadot (65-67)
packages/core/stellar/src/utils/zip-test.ts (1)
  • asString (15-15)
packages/core/solidity/src/zip-hardhat-polkadot.ts (2)
packages/core/solidity/src/zip-hardhat.ts (1)
  • HardhatZipGenerator (91-307)
packages/core/solidity/hardhat.config.js (1)
  • SOLIDITY_VERSION (11-11)
packages/core/solidity/src/zip-hardhat.ts (3)
packages/core/solidity/src/contract.ts (2)
  • Contract (3-14)
  • FunctionArgument (65-68)
packages/core/solidity/src/utils/format-lines.ts (1)
  • formatLinesWithSpaces (9-11)
packages/core/solidity/src/print.ts (1)
  • printContract (23-57)
⏰ 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: build (solidity, default)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (14)
.nvmrc (1)

1-1: Node.js 22 upgrade aligns with PR requirements.

Node.js v22 has officially moved into Active LTS status and the node.js 22 will enter long-term support (LTS) in October, making this a stable choice for production. The upgrade from Node 20 to 22 supports the Hardhat Polkadot plugin requirement mentioned in PR objectives.

.github/actions/setup/action.yml (1)

6-8: GitHub Actions setup properly updated for Node.js 22.

The action correctly updates both the setup-node version to v5.0.0 and Node.js version to 22, maintaining consistency with the .nvmrc change. The commit hash ensures reproducible builds.

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

1-201: Test snapshot looks comprehensive and properly structured.

The snapshot covers all essential files for a Hardhat Polkadot project including contracts, configuration, package.json, ignition modules, tests, and documentation. The content demonstrates proper integration of Polkadot-specific configuration like polkavm: true and Polkadot Revive-specific settings.

packages/core/solidity/src/zip-hardhat.test.ts.md (2)

107-107: Comment improvement enhances clarity.

The update from "Set addresses for the contract arguments below" to "Set values for the constructor arguments below" improves clarity and accuracy, as constructor arguments aren't limited to addresses.

Also applies to: 266-266, 373-373, 465-465, 546-546, 644-645, 667-667


645-645: Array format for unsafeAllow corrects Hardhat Upgrades API usage.

The change from { unsafeAllow: 'constructor' } to { unsafeAllow: ['constructor'] } aligns with the correct Hardhat Upgrades API format, which expects an array of strings rather than a single string.

Also applies to: 667-667

packages/core/solidity/zip-env-hardhat-polkadot.ts (1)

1-1: Clean re-export structure maintains API consistency.

The simple re-export pattern follows the established convention for environment-specific entry points and properly exposes the Polkadot Hardhat functionality.

packages/ui/src/polkadot/App.svelte (3)

7-7: Type imports added for enhanced type safety.

Adding explicit type imports for Contract and GenericOptions improves type safety for the new override functions.


12-14: Dynamic import implementation enables lazy loading.

The dynamic import pattern efficiently loads the Polkadot-specific module only when needed, reducing initial bundle size while maintaining functionality.


23-29: Function-based override provides conditional Hardhat zip generation.

The implementation properly uses the new override API:

  • omitZipHardhat function correctly excludes upgradeable contracts (which aren't supported for Polkadot per PR objectives)
  • overrideZipHardhat async function properly awaits the dynamic module and delegates to zipHardhatPolkadot
packages/core/solidity/zip-env-hardhat-polkadot.js (1)

1-1: Simple proxy module follows established patterns.

The CommonJS proxy correctly routes to the built distribution file, maintaining consistency with other environment entry points in the project.

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

146-146: LGTM! Clean migration to function-based override

The change from a boolean check to a function call overrides.omitZipHardhat(opts) provides better flexibility for conditional logic based on the options.


204-207: Good implementation of override pattern for Hardhat zip generation

The conditional logic properly checks for the presence of overrideZipHardhat and falls back to the default zipHardhat when not provided. This allows ecosystem-specific customization while maintaining backward compatibility.

packages/ui/src/solidity/overrides.ts (1)

24-29: Well-designed extensibility for Hardhat zip generation

The conversion of omitZipHardhat to a function and addition of overrideZipHardhat provides a clean extension point for ecosystem-specific Hardhat configurations. The optional nature of overrideZipHardhat maintains backward compatibility.

packages/core/solidity/src/zip-hardhat.ts (1)

91-307: Excellent refactoring to class-based architecture

The refactoring from procedural code to the HardhatZipGenerator class provides excellent extensibility, as demonstrated by the Polkadot subclass. The protected methods allow for selective overriding while maintaining the core logic.

"@nomicfoundation/hardhat-toolbox": "^6.1.0",
"hardhat": "^2.16.1"
}
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

License should be MIT for consistency.

The package.json uses "ISC" license, but Line 117 in the test snapshot shows "MIT". This inconsistency should be resolved for consistency with the rest of the project.

Apply this diff to fix the license inconsistency:

-  "license": "ISC",
+  "license": "MIT",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
}
"license": "MIT",
}
🤖 Prompt for AI Agents
In packages/core/solidity/src/environments/hardhat/polkadot/package.json around
line 17, the "license" field is set to "ISC" but the project snapshot and
standard use "MIT"; update the license value from "ISC" to "MIT" in the
package.json to ensure consistency across the repository.

}
}

const command = `cd "${tempFolder}" && npm install && npx hardhat compile`;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Avoid shell injection vulnerabilities with unsanitized paths

Using string interpolation in shell commands with tempFolder from the OS temp directory could be vulnerable to command injection if the path contains special characters.

Use proper escaping or the programmatic API instead:

-  const command = `cd "${tempFolder}" && npm install && npx hardhat compile`;
+  const cwd = tempFolder;
+  const exec = util.promisify(child.exec);
+  
+  // Run npm install
+  await exec('npm install', { cwd });
+  // Run hardhat compile
+  const result = await exec('npx hardhat compile', { cwd });

Alternatively, use child_process.spawn with proper argument arrays to avoid shell interpretation entirely.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/core/solidity/src/zip-hardhat-polkadot.test.ts around line 91, the
test builds a shell command by interpolating tempFolder into a single command
string which can be exploited via shell injection; replace this pattern with a
programmatic child_process API (e.g., child_process.spawn or execFile) and run
the commands with argument arrays and cwd set to tempFolder (or call npm and npx
as separate spawn calls) so no shell interpretation occurs and tempFolder is not
passed to a shell parser; ensure spawn is called without shell: true and handle
stdout/stderr/promises accordingly.

Comment on lines +12 to +34
protected getHardhatConfigJsonString(): string {
return `\
{
solidity: '${SOLIDITY_VERSION}',
resolc: {
compilerSource: 'npm',
},
networks: {
hardhat: {
polkavm: true,
nodeConfig: {
nodeBinaryPath: 'INSERT_PATH_TO_SUBSTRATE_NODE',
rpcPort: 8000,
dev: true,
},
adapterConfig: {
adapterBinaryPath: 'INSERT_PATH_TO_ETH_RPC_ADAPTER',
dev: true,
},
},
},
}`;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Placeholder values may cause confusion for users

The hardhat config contains placeholder paths 'INSERT_PATH_TO_SUBSTRATE_NODE' and 'INSERT_PATH_TO_ETH_RPC_ADAPTER' that users need to manually replace. This could lead to confusion if users try to run commands without first replacing these values.

Consider adding validation or more prominent warnings in the generated README to ensure users understand these must be replaced before use. You could also consider making these environment variables with clear error messages when not set.

@ericglau ericglau changed the title Add Hardhat Polkadot zip option Add download Hardhat Polkadot zip option Sep 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant