Skip to content

Conversation

CoveMB
Copy link
Contributor

@CoveMB CoveMB commented Sep 19, 2025

Fixes #662

Summary

  • Fixes Remix URL code parameter encoding to be reliably decodable, including both Unicode and special characters.
  • Adds focused unit tests for remixURL behavior and wires UI tests into CI.

Motivation

  • Previous encoding could be brittle across environments when decoding via atob (decodeURIComponent(...)). This ensures consistent, binary-safe Base64 and trims padding to keep the URL compact.

Key Changes

  • packages/ui/src/solidity/remix.ts: Update encoding to Base64 over UTF-8 bytes and store once as encodedCode; keep padding trimmed.
  • packages/ui/src/solidity/remix.node.test.ts: Add Node tests verifying:
    • code param decodes back to original source.
    • deployProxy flag behavior.
  • packages/ui/package.json: Add test script using Node’s test runner with tsx.
  • package.json: Add test:ui script and tsx dev dependency.
  • .github/workflows/test.yml: Add dedicated ui job to run UI tests.
  • yarn.lock: Update due to new dev dependency.

Behavioral Impact

  • User-facing: Only affects the generated Remix URL’s code parameter; behavior is otherwise unchanged.
  • Backward compatibility: No breaking changes expected.

How To Test
Before Remix side MR is merged

  • create any contract
    • Open in remix, it should decode
      After Remix side MR is merged
  • In ui make a Solidity Account contract with modules AND use a special character a contract name
    • Open in remix, it should decode

** Note**

Copy link
Contributor

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

Adds a UI test job to CI, introduces root and UI test scripts, configures AVA with ts-node, and updates Remix URL generation to cross-environment base64 encode source without invalid characters. Adds unit tests validating code encoding/decoding and deployProxy flag handling.

Changes

Cohort / File(s) Summary
CI: UI tests in workflow
\.github/workflows/test.yml
Adds a new ui job: checks out repo, runs local setup action, executes yarn test in packages/ui. Positioned between mcp and build jobs.
Root scripts
package.json
Adds test:ui script to run tests in packages/ui via yarn --cwd ./packages/ui test.
UI test setup (AVA + ts-node)
packages/ui/package.json, packages/ui/ava.config.js, packages/ui/ts-node-register.cjs, packages/ui/tsconfig.test.json
Adds AVA-based test runner: scripts.test: "ava", devDeps ava, ts-node; AVA config for TS (extensions: ['ts'], require: ['./ts-node-register.cjs'], timeout: '10m', workerThreads: false); ts-node register targeting tsconfig.test.json; test tsconfig with NodeNext and DOM libs.
Remix URL encoding fix
packages/ui/src/solidity/remix.ts
Replaces prior two-step encoding with a cross-environment base64 encoder (browser btoa with TextEncoder, Node Buffer fallback), trims padding, and sets code search param directly to the encoded value.
UI unit tests
packages/ui/src/solidity/remix.test.ts
Adds tests for remixURL: verifies base64-encoded code decodes to original, checks deployProxy flag behavior, and handles special characters/multi-line sources.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as UI (Wizard)
  participant FN as remixURL()
  participant ENC as Base64 Encoder
  participant URL as URL

  User->>UI: Generate Remix link
  UI->>FN: remixURL(source, deployProxy?)
  note over FN: New cross-environment encoding path
  FN->>ENC: Encode UTF-8 source to base64 (no padding)
  ENC-->>FN: encodedCode
  FN->>URL: Create URL and set search params (code, deployProxy?)
  URL-->>UI: Remix URL
  UI-->>User: Open in Remix link
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

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 (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title “Remix encoding fix” succinctly captures the primary change of the pull request, focusing on the fix to the Remix URL encoding logic without extraneous details.
Linked Issues Check ✅ Passed The pull request updates the encoding in packages/ui/src/solidity/remix.ts to use UTF-8–safe Base64, adds comprehensive unit tests for code decoding and deployProxy behavior, and wires those tests into the CI workflow, thereby fulfilling the core coding objectives of issue #662.
Out of Scope Changes Check ✅ Passed All added and modified files—including CI workflow updates, package scripts, test configurations, and the remixURL implementation—directly support the encoding fix and associated testing objectives, with no unrelated or extraneous changes detected.
Description Check ✅ Passed The description clearly outlines the purpose of the encoding fix, the added unit tests for remixURL, the CI integration for UI tests, and the motivation behind the changes, all of which align directly with the implemented code modifications.

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.

@CoveMB CoveMB marked this pull request as ready for review September 19, 2025 01:40
@CoveMB CoveMB requested review from a team as code owners September 19, 2025 01:40
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 (2)
package.json (1)

32-32: tsx only at root couples UI tests to hoisting

UI package executes node --import tsx but doesn’t declare tsx itself. Add tsx to packages/ui devDependencies to avoid breakage under non-hoisted installs or PnP.

Apply in packages/ui/package.json:

   "devDependencies": {
+    "tsx": "^4.19.2",
     "@rollup/plugin-alias": "^5.0.0",
packages/ui/package.json (1)

12-13: Expose a top-level test:ui in this workspace (optional) and declare tsx locally

Scripts look good. Consider also adding tsx to this package’s devDependencies (see root comment) to decouple from hoisting.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f075b6 and 6933f06.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (5)
  • .github/workflows/test.yml (1 hunks)
  • package.json (3 hunks)
  • packages/ui/package.json (2 hunks)
  • packages/ui/src/solidity/remix.node.test.ts (1 hunks)
  • packages/ui/src/solidity/remix.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/ui/src/solidity/remix.node.test.ts (1)
packages/ui/src/solidity/remix.ts (1)
  • remixURL (1-13)
⏰ 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). (8)
  • GitHub Check: check
  • GitHub Check: build (stylus, default)
  • GitHub Check: build (cairo, default)
  • GitHub Check: build (stellar, compile)
  • GitHub Check: build (stellar, default)
  • GitHub Check: build (solidity, default)
  • GitHub Check: mcp
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (5)
package.json (1)

10-10: LGTM: added test:ui script

This nicely scopes UI tests and aligns with the new CI job.

.github/workflows/test.yml (1)

43-52: Make Node version explicit for the UI job

node --import tsx --test depends on recent Node. Either ensure your setup action pins Node ≥18 (preferably 20+) or add an explicit actions/setup-node step here for determinism.

If setup already pins Node ≥20, ignore.

packages/ui/src/solidity/remix.node.test.ts (3)

12-21: LGTM: round‑trip sanity check

Covers the basic path and asserts presence of the code param.


23-31: LGTM: deployProxy flag behavior

Correct: only set when upgradeable is true.


33-96: LGTM: complex/Unicode contract case

Good coverage for SPDX, imports, inheritance, and Unicode literals (e.g., emoji).

Copy link

socket-security bot commented Sep 19, 2025

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

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​openzeppelin/​hardhat-upgrades@​3.9.19910010087100
Added@​openzeppelin/​contracts-upgradeable@​5.4.010010010094100

View full report

Copy link

socket-security bot commented Sep 19, 2025

Caution

Review the following alerts detected in dependencies.

According to your organization's Security Policy, you must resolve all "Block" alerts before proceeding. It is recommended to resolve "Warn" alerts too. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Block Low
undici@6.21.3 is a AI-detected potential code anomaly.

Notes: The analyzed code appears to implement a standard in-memory cache batch operation flow (put/delete) with careful handling of response bodies by buffering and storing bytes for caching. No signs of malware, data exfiltration, backdoors, or obfuscated behavior were found. The primary security considerations relate to memory usage from buffering potentially large response bodies and ensuring robust validation within batch operations to prevent cache state corruption. Overall risk is moderate, driven by in-memory data handling rather than external communication.

Confidence: 1.00

Severity: 0.60

From: packages/core/solidity/src/environments/hardhat/upgradeable/package-lock.jsonnpm/@openzeppelin/hardhat-upgrades@3.9.1npm/undici@6.21.3

ℹ Read more on: This package | This alert | What is an AI-detected potential code anomaly?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: An AI system found a low-risk anomaly in this package. It may still be fine to use, but you should check that it is safe before proceeding.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/undici@6.21.3. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
buffer@4.9.2 has Obfuscated code.

Confidence: 0.96

Location: Package overview

From: packages/core/solidity/src/environments/hardhat/upgradeable/package-lock.jsonnpm/@openzeppelin/hardhat-upgrades@3.9.1npm/buffer@4.9.2

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/buffer@4.9.2. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@CoveMB
Copy link
Contributor Author

CoveMB commented Sep 24, 2025

@coderabbitai review

Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CoveMB CoveMB enabled auto-merge (squash) September 24, 2025 20:55
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/ui/ts-node-register.cjs (1)

6-9: Optional: speed up tests with swc transpiler

You can shave test time by enabling ts-node’s swc transpiler (keep transpileOnly). Requires adding @swc/core as a devDependency.

Apply this diff (and add @swc/core devDependency):

 require('ts-node').register({
   transpileOnly: true,
   project: path.join(__dirname, 'tsconfig.test.json'),
+  transpiler: 'ts-node/transpilers/swc-experimental',
 });
packages/ui/src/solidity/remix.test.ts (1)

5-9: Make decoder tolerant of trimmed padding

Since URLs trim “=”, some atob implementations require re-padding. Re-pad defensively to avoid environment-specific flakiness while still mirroring Remix’s flow.

Apply this diff:

-const decodeBase64 = (b64Payload: string) => {
-  const raw = atob(decodeURIComponent(b64Payload));
+const decodeBase64 = (b64Payload: string) => {
+  const decoded = decodeURIComponent(b64Payload);
+  const pad = (4 - (decoded.length % 4)) % 4;
+  const padded = pad ? decoded + '='.repeat(pad) : decoded;
+  const raw = atob(padded);
   const bytes = Uint8Array.from(raw, c => c.charCodeAt(0));
   return new TextDecoder().decode(bytes);
 };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6933f06 and 28afbb6.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (7)
  • package.json (2 hunks)
  • packages/ui/ava.config.js (1 hunks)
  • packages/ui/package.json (3 hunks)
  • packages/ui/src/solidity/remix.test.ts (1 hunks)
  • packages/ui/src/solidity/remix.ts (1 hunks)
  • packages/ui/ts-node-register.cjs (1 hunks)
  • packages/ui/tsconfig.test.json (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • packages/ui/tsconfig.test.json
  • packages/ui/ava.config.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/ui/package.json
  • package.json
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-18T19:26:06.112Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#652
File: packages/core/confidential/print-versioned.js:1-1
Timestamp: 2025-09-18T19:26:06.112Z
Learning: CJS shims like `module.exports = require('./dist/print-versioned')` in packages/core/confidential are expected to be CJS-only and are used specifically within packages/ui, not as general-purpose exports requiring conditional exports mapping.

Applied to files:

  • packages/ui/ts-node-register.cjs
🪛 GitHub Check: format-lint
packages/ui/src/solidity/remix.ts

[failure] 10-10:
Unexpected any. Specify a different type


[failure] 7-7:
Unexpected any. Specify a different type

⏰ 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). (1)
  • GitHub Check: build (solidity, default)
🔇 Additional comments (2)
packages/ui/src/solidity/remix.ts (2)

16-16: LGTM: using URLSearchParams for code param

This ensures proper percent-encoding of reserved characters.


4-14: Fix unbounded spread and remove any casts; resolve lint failures and avoid stack/heap issues

  • String.fromCharCode(...bytes) on the full Uint8Array can overflow the call stack for large sources.
  • ESLint “Unexpected any” on (globalThis as any) is failing format-lint.
  • Use chunked conversion and typed access to global features. This keeps your cross-runtime intent, preserves “trim padding,” and makes lint green.

Apply this diff:

-  // Encode to base64 in a way that works in both browser and Node.
-  const encodedCode = ((): string => {
-    // Prefer browser btoa when available
-    if (typeof (globalThis as any).btoa === 'function') {
-      const bytes = new TextEncoder().encode(code);
-      const binary = String.fromCharCode(...bytes);
-      return (globalThis as any).btoa(binary).replace(/=*$/, '');
-    }
-    // Fallback to Node Buffer
-    return Buffer.from(code, 'utf8').toString('base64').replace(/=*$/, '');
-  })();
+  // Cross‑runtime Base64 over UTF‑8 bytes. Trims "=" padding to keep URLs compact.
+  const encodedCode = ((): string => {
+    const g = globalThis as unknown as {
+      btoa?: (data: string) => string;
+      Buffer?: { from(input: string, encoding: string): { toString(encoding: 'base64'): string } };
+    };
+    // Prefer Node/Buffer when available (works in Node and many bundler environments)
+    if (g.Buffer && typeof g.Buffer.from === 'function') {
+      return g.Buffer.from(code, 'utf8').toString('base64').replace(/=*$/, '');
+    }
+    // Browser path: build the binary string in chunks to avoid call‑stack overflow
+    if (g.btoa && typeof TextEncoder !== 'undefined') {
+      const bytes = new TextEncoder().encode(code);
+      let binary = '';
+      const CHUNK = 0x8000; // 32k chunks
+      for (let i = 0; i < bytes.length; i += CHUNK) {
+        binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
+      }
+      return g.btoa(binary).replace(/=*$/, '');
+    }
+    throw new Error('No Base64 encoder available in this environment');
+  })();

@@ -1,11 +1,9 @@
export function remixURL(code: string, upgradeable = false, overrideRemixURL?: string): URL {
const remix = new URL(overrideRemixURL ?? 'https://remix.ethereum.org');
export function remixURL(code: string, upgradeable = false): URL {
Copy link
Member

Choose a reason for hiding this comment

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

This needs to keep the overrideRemixURL?: string parameter and use it on line 2, since it is required for Polkadot Wizard to use the Polkadot fork of Remix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Open in Remix has encoding error for some contracts
2 participants