Skip to content

Conversation

@0xisk
Copy link
Member

@0xisk 0xisk commented Dec 3, 2025

Types of changes

What types of changes does your code introduce to OpenZeppelin Midnight Contracts?
Put an x in the boxes that apply

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation Update (if none of the other choices apply)

Fixes #???

This PR follows the same contracts structure in the compact-contracts repo, and also started using compact-tools as a submodule.

PR Checklist

  • I have read the Contributing Guide
  • I have added tests that prove my fix is effective or that my feature works
  • I have added documentation of new methods and any new behavior or changes to existing behavior
  • CI Workflows Are Passing

Further comments

If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc...

Summary by CodeRabbit

  • New Features

    • Added shielded fungible token support with minting and burning operations
    • Enhanced access control system with role-based permissions
  • Chores

    • Reorganized contract architecture and dependencies
    • Updated module resolution and build configuration
    • Consolidated workspace package structure

✏️ Tip: You can customize this high-level summary in your review settings.

@0xisk 0xisk requested a review from a team as a code owner December 3, 2025 13:38
@0xisk 0xisk changed the title refactor(contracts): follow compact-contracts contracts file structure refactor(contracts): follow compact-contracts contracts file structure Dec 3, 2025
@0xisk 0xisk self-assigned this Dec 3, 2025
@0xisk
Copy link
Member Author

0xisk commented Dec 3, 2025

TODO: still need to check why the actions are failing.

} from '../artifacts/Index/contract/index.cjs';

import type { Role } from '../../../artifacts/access/Index/contract/index.cjs';
// TODO: (team): I noticed that we are using the mock contract's ledger type here, but I am not sure if this is correct way.
Copy link
Contributor

Choose a reason for hiding this comment

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

Yup, we have to import from the mock contract's artifact file because it's the top level contract. The top level contract artifact file is what exposes the methods and type definitions required to define contracts in TS. The base module artifact file is typically empty

Suggested change
// TODO: (team): I noticed that we are using the mock contract's ledger type here, but I am not sure if this is correct way.

Copy link
Member Author

@0xisk 0xisk Dec 4, 2025

Choose a reason for hiding this comment

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

The issue I see with this pattern that sometimes (most of the time maybe) when we write Mock contracts, we don't export ALL the ledger variables. And we end up defining an exported Ledger type in ts that is not mapping the whole ledger types in the mock file. For example: If we look at the AccessControl.mock.compact contract we will see the exported are:

export { AccessControl_hashUserRole, roleCommits, isInitialized, index, Role };
However, the list of all the ledger vars from the IAccessControl.compact are:
/**
* @description Indicates whether the contract has been initialized.
* @type {Boolean}
*/
export ledger isInitialized: Boolean;
/**
* @description Merkle tree storing commitments of user-role pairs, with a fixed depth of 10.
* @type {MerkleTree<10, Bytes<32>>}
*/
export ledger roleCommits: MerkleTree<10, Bytes<32>>;
/**
* @description A set of nullifiers tracking used user-role pairs to prevent duplicate role assignments.
* @type {Set<Bytes<32>>}
*/
export ledger roleNullifiers: Set<Bytes<32>>;
/**
* @description Counter tracking the next available index for inserting into the role tree.
* @type {Counter}
*/
export ledger index: Counter;
, and therefore that what we get as a type Ledger from the artifacts of the mock file:

export type Ledger = {
  readonly isInitialized: boolean;
  roleCommits: {
    isFull(): boolean;
    checkRoot(rt_0: { field: bigint }): boolean;
    root(): __compactRuntime.MerkleTreeDigest;
    firstFree(): bigint;
    pathForLeaf(index_0: bigint, leaf_0: Uint8Array): __compactRuntime.MerkleTreePath<Uint8Array>;
    findPathForLeaf(leaf_0: Uint8Array): __compactRuntime.MerkleTreePath<Uint8Array> | undefined
  };
  readonly index: bigint;
}

You can notice that there is a missing ledger type which is roleNullifiers. Imo that is a misleading type as it does not reflect ALL the ledger vars.

That issue I think it should be tracked by the Compiler in the first place, I think the compiler should auto-export all the ledger vars defined in any module (even non-top-level modules) -If you agree with me on this, let's open this discussion with the language team.
At the mean time, I think we need to rethink about how to mitigate this either by introducing another better way of exporting the Ledger/Types vars seperatly or by adding a strict rule of reviewing the *.mock.compact exported vars and compare it with the Ledger. I am leaning towards not depending on the mock file at all, as their main purpose is for testing, and as we need the type Ledger in the definition of the WitnessContext, I would lean towards the first suggestion (which is not clear yet). Again ideally imo that should be the Compiler job. cc: @andrew-fleming

Copy link
Contributor

Choose a reason for hiding this comment

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

That issue I think it should be tracked by the Compiler in the first place, I think the compiler should auto-export all the ledger vars defined in any module (even non-top-level modules) -If you agree with me on this, let's open this discussion with the language team.

This would be especially useful for deeply nested modules. I think in practice when a ledger var is exported from a module developers expect it to be exposed in the TS interface.

Copy link
Contributor

Choose a reason for hiding this comment

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

At the mean time, I think we need to rethink about how to mitigate this either by introducing another better way of exporting the Ledger/Types vars seperatly or by adding a strict rule of reviewing the *.mock.compact exported vars and compare it with the Ledger. I am leaning towards not depending on the mock file at all, as their main purpose is for testing, and as we need the type Ledger in the definition of the WitnessContext, I would lean towards the first suggestion (which is not clear yet). Again ideally imo that should be the Compiler job.

Ideally, we'd have a codegen tool that generates all of this boilerplate for us. It would be a great addition to compact-tools, but likely require a couple weeks of engineering work.

Copy link
Contributor

Choose a reason for hiding this comment

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

That issue I think it should be tracked by the Compiler in the first place, I think the compiler should auto-export all the ledger vars defined in any module (even non-top-level modules) -If you agree with me on this, let's open this discussion with the language team.

Forgive me, this seems dangerous. Automatically exposing state variables will make it easier for devs to unwittingly break invariants. I think being explicit about what's exposed both forces the contract author to consider this and allows the user to see it. Admittedly, being explicit adds a tiny bit of friction to development, but to me, this is a worthwhile tradeoff with security > convenience

Regarding the main point with there being a missing ledger type, AFAICT this seems more like a testing/tooling issue rather than a protocol one. The missing ledger type is a problem if we're trying to view state updates, no? If we don't use it to validate assertions, then we probably don't need to expose it in the mock. LMK if I'm missing something

I think the optimal solution (or one of the better solutions) would be something like this https://github.com/frangio/hardhat-exposed. Instead of the compiler automatically exposing everything, we have tooling that does this in a testing env

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you @andrew-fleming and @emnul for your responses.

Forgive me, this seems dangerous. Automatically exposing state variables will make it easier for devs to unwittingly break invariants. I think being explicit about what's exposed both forces the contract author to consider this and allows the user to see it. Admittedly, being explicit adds a tiny bit of friction to development, but to me, this is a worthwhile tradeoff with security > convenience

@andrew-fleming could you please elaborate more on this? Not sure if I get the security concern here.

Regarding the main point with there being a missing ledger type, AFAICT this seems more like a testing/tooling issue rather than a protocol one. The missing ledger type is a problem if we're trying to view state updates, no? If we don't use it to validate assertions, then we probably don't need to expose it in the mock. LMK if I'm missing something

I think I see the issue more here: https://github.com/OpenZeppelin/compact-contracts/blob/a8e28aec27c0458dd68d963a68b021fea8b83e98/contracts/src/access/test/simulators/ZOwnablePKSimulator.ts#L48 Where the simulator calls the function ledger that returns the type Ledger to extract the public state. So if a ledger variable was not exported at the end in the top-level contract it won't be visible here, that is currently is used for testing. However, in the frontend we can do the same interface idea to inspect the contract on the frontend and if the type [Ledger](https://github.com/OpenZeppelin/midnight-apps/blob/32e78cb4619a0ced162c9bdfc02c1951e36afc90/apps/lunarswap-ui/lib/lunarswap-context.tsx#L4) is missing a ledger variable I will need to get back to the compact contract to export that variable.
I am not sure if in Compact it is the same notion like in Solidity when it comes to define the state with internal, public, or private.

I think the optimal solution (or one of the better solutions) would be something like this frangio/hardhat-exposed. Instead of the compiler automatically exposing everything, we have tooling that does this in a testing env

But that is for exporting the internal functions, so in our case would be good for testing the internal circuits, I think that is diff from exporting the ledger variables.

I think I might be just confusing the idea of exporting with the Solidity modifiers

Copy link
Member Author

Choose a reason for hiding this comment

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

Re-evaluating the Placement of Witness Scripts in compact-contracts

After looking at this again, I realized my initial confusion came from the fact that the src/witnesses/*.ts files in compact-contracts live inside src/ rather than inside the test directory. At first, I assumed these witness scripts were meant to be part of the package’s public API and would be exported from @openzeppelin/compact-contracts. But using the ShieldedAccessControl example made it clear that this isn’t the case.

For instance, in the shielded-access-control branch,
contracts/src/access/witnesses/ShieldedAccessControlWitnesses.ts
depends directly on the exports of the MockShieldedAccessControl contract. This dependency is only meaningful in a testing or simulation context — not in an actual production Compact module.

That’s why it now seems that these witness scripts are essentially mocks for private data, similar in nature to the MODULE.mock.compact artifacts. They help exercise circuits and simulate private inputs, but they are not part of the runtime interface that gets shipped to developers.

Given that, their placement inside src/ is misleading. From the outside, it makes them appear as part of the library’s official surface area, even though in practice they behave like test-only witness implementations. Because they depend on mock contracts and are not meant to be consumed by users, their natural place seems to be inside the module’s test directory next to the mocks and simulators. Let me know wdyt.

I will reply in another message regarding the exported ledger discussion, since that’s a separate concern.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is my second point, and it's more complex. I wrote it here so we can discuss it in the discussions easier if it makes sense we can then open it as an issue. #272

Copy link
Contributor

@emnul emnul left a comment

Choose a reason for hiding this comment

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

Left a few comments that should be discussed before PR is finalized

@0xisk 0xisk force-pushed the refactor/contracts-structure branch from c4d17fa to 101342d Compare December 9, 2025 13:45
@coderabbitai
Copy link

coderabbitai bot commented Dec 9, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

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

Walkthrough

This pull request restructures the contracts monorepo by consolidating nested workspace packages into a unified root-level structure, relocating source files to centralized paths, replacing external package dependencies with local module references, and updating module resolution to ES module format with explicit .js file extensions.

Changes

Cohort / File(s) Summary
Submodule & Root Package Addition
.gitmodules, compact-tools, contracts/package.json
Added submodule reference to compact-tools repository and introduced root-level package manifest for the contracts workspace with shared build/test/lint scripts and dependencies.
Deleted Workspace Package Configs
contracts/access/package.json, contracts/compact-std/package.json, contracts/math/package.json, contracts/shielded-token/package.json, contracts/structs/package.json
Removed individual package.json manifests from all nested contract packages, consolidating package metadata into the root contracts/package.json.
Deleted Build & TypeScript Configs
contracts/*/tsconfig*.json, contracts/*/vitest.config.ts, contracts/*/.lintstagedrc.json, contracts/*/biome.json
Removed local TypeScript, Vitest, and linting configurations from access, compact-std, math, shielded-token, and structs directories.
Root TypeScript & Vitest Configuration
contracts/tsconfig.json, contracts/tsconfig.build.json, contracts/vitest.config.ts
Added root-level TypeScript configurations (targeting ES2022, enabling strict mode, declaration generation) and Vitest config with verbose reporting.
Access Control Module Refactoring
contracts/src/access/AccessControl.compact, contracts/src/access/interfaces/IAccessControl.compact, contracts/src/access/Index.compact, contracts/src/access/test/AccessControl.mock.compact
Extracted public ledger state and Role enum into new IAccessControl.compact interface, renamed witness functions with wit_ prefix, removed public ledger exports from main contract, and created index file for centralized re-exports.
Access Control TypeScript Updates
contracts/src/access/index.ts, contracts/src/access/types/ledger.ts, contracts/src/access/types/role.ts, contracts/src/access/witnesses/interface.ts, contracts/src/access/witnesses/AccessControlWitnesses.ts, contracts/src/access/test/*
Updated import paths to .js extensions, changed function names to wit_ prefixed variants, updated type imports to use local StandardLibrary module instead of external packages, and adjusted all call sites to new naming conventions.
Removed Deleted Access Files
contracts/access/src/Index.compact, contracts/access/tsconfig.build.json, contracts/access/tsconfig.json, contracts/access/vitest.config.ts, contracts/access/.lintstagedrc.json, contracts/access/package.json
Deleted all configuration and source files from original contracts/access/ directory structure.
Math Module Import Path Updates
contracts/src/math/index.ts, contracts/src/math/test/*.ts, contracts/src/math/test/*Simulator.ts, contracts/src/math/utils/*.ts, contracts/src/math/witnesses/*.ts
Updated all import paths to use explicit .js extensions and adjust artifact references from ../artifacts/... to ../../../artifacts/math/... structure.
Removed Math Package Files
contracts/math/package.json, contracts/math/tsconfig*.json, contracts/math/vitest.config.ts, contracts/math/.lintstagedrc.json, contracts/math/biome.json
Deleted configuration files from nested contracts/math/ directory.
Shielded Token Module Reorganization
contracts/src/shielded-token/ShieldedFungibleToken.compact, contracts/src/shielded-token/index.ts, contracts/src/shielded-token/openzeppelin/ShieldedERC20.compact, contracts/src/shielded-token/types/index.ts, contracts/src/shielded-token/witnesses/index.ts
Introduced new ShieldedFungibleToken.compact file with mint/burn circuits, updated artifact import paths, added type exports, and corrected module references.
Shielded Token TypeScript & Test Updates
contracts/src/shielded-token/test/*.ts, contracts/src/shielded-token/openzeppelin/Utils.compact
Updated import paths to .js extensions, adjusted artifact references to new path structure, and applied minor formatting adjustments.
Removed Shielded Token Package Files
contracts/shielded-token/package.json, contracts/shielded-token/tsconfig*.json, contracts/shielded-token/README.md, contracts/shielded-token/biome.json, contracts/shielded-token/.lintstagedrc.json
Deleted configuration and documentation files from nested contracts/shielded-token/ directory.
Structs Module Updates
contracts/src/structs/index.ts, contracts/src/structs/test/*.ts, contracts/src/structs/utils/test.ts, contracts/src/structs/witnesses/QueueWitnesses.ts
Updated import paths to .js extensions and adjusted artifact references to centralized path structure.
Removed Structs Package Files
contracts/structs/package.json, contracts/structs/tsconfig*.json, contracts/structs/vitest.config.ts, contracts/structs/.lintstagedrc.json, contracts/structs/biome.json
Deleted configuration files from nested contracts/structs/ directory.
Removed Compact-Std Package Files
contracts/compact-std/package.json, contracts/compact-std/tsconfig*.json, contracts/compact-std/vitest.config.ts, contracts/compact-std/.lintstagedrc.json, contracts/compact-std/biome.json
Deleted configuration files from nested contracts/compact-std/ directory.
Types & StandardLibrary Updates
contracts/src/types/StandardLibrary.ts, contracts/src/types/StandardLibrary.test.ts
Updated export source from ./artifacts/Index/contract/index.cjs to ../../artifacts/types/Std/contract/index.cjs and adjusted import paths to .js extensions.
Workspace Configuration Updates
package.json, pnpm-workspace.yaml
Changed pnpm workspace globs from contracts/* to contracts, simplified build/test/type scripts to filter on ./contracts instead of ./contracts/*, and updated compact scripts to use Turbo-based execution.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • Access Control interface extraction: Verify that moving Role enum and ledgers into IAccessControl.compact and renaming witness functions (getRolePathwit_getRoleMerklePath, etc.) maintains consistency across all 15+ referencing files in the access module.
  • Import path reorganization: The shift from external @openzeppelin/midnight-apps-* packages to local relative paths (e.g., ../../artifacts/math/... structures) needs verification that all paths resolve correctly and no cyclic dependencies are introduced. Affected across access, math, shielded-token, structs, and types modules.
  • Artifact path corrections: Multiple files updated artifact import paths to new hierarchical structure (../../../artifacts/<module>/...); confirm all .cjs and .d.cts files exist at new paths and match expected export signatures.
  • StandardLibrary migration: Verify that replacing external @openzeppelin/midnight-apps-compact-std imports with local StandardLibrary.js module correctly exposes all required types (Maybe, MerkleTreePath) used throughout codebase.
  • Workspace restructuring: Test that the consolidated root contracts/package.json and updated pnpm-workspace.yaml glob patterns (contracts instead of contracts/*) correctly identify all workspace members and scripts execute as expected.
  • Module extension consistency: ~50+ files updated to include explicit .js extensions in import paths; spot-check a sample to ensure no mixed or missing extensions that could break ES module resolution.

Poem

🐰 The warren reorganized its burrow today,
Packages consolidated, paths found their way,
Local imports over external stores,
Witness functions wearing wit_ like new doors,
From fragmented nests to a unified space,
The contracts now share a cleaner base!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective: refactoring the contracts directory to follow the file structure conventions from the compact-contracts repository.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

Copy link

@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: 6

Caution

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

⚠️ Outside diff range comments (2)
contracts/src/math/witnesses/Uint256.ts (1)

128-199: Fix JSDoc return type in divU128Locally

Line 133 incorrectly documents the return type as DivResultU64 when it should be DivResultU128:

-   * @returns A tuple of the unchanged private state and a DivResultU64 with quotient and remainder.
+   * @returns A tuple of the unchanged private state and a DivResultU128 with quotient and remainder.

Additionally, all div* helpers assume a non-zero divisor without validation. If circuit constraints guarantee this, add a clarifying comment; otherwise, consider documenting the requirement explicitly or adding a check.

contracts/src/access/witnesses/AccessControlWitnesses.ts (1)

46-65: Remove unused wit_getRoleMerklePath helper with incorrect signature

The helper function at lines 73–79 in AccessContractPrivateState has an incorrect signature that doesn't match the IAccessControlWitnesses interface. It takes a user: ZswapCoinPublicKey and returns Role, whereas the interface specifies userRoleCommit: Uint8Array and Maybe<MerkleTreePath<Uint8Array>>. This helper is never called in the codebase and should be removed entirely. The actual witness method implementation at lines 143–168 correctly uses the proper key format (userRoleCommit.toString()) and return type.

♻️ Duplicate comments (3)
contracts/src/shielded-token/openzeppelin/ShieldedERC20.compact (1)

126-152: Address the type inconsistency and convert TODO to a tracked issue.

The TODO comment documents a compilation constraint, but there's a functional inconsistency:

  • mint accepts Uint<64> (line 137)
  • burn accepts Uint<128> (line 165)
  • _totalSupply is Uint<128> (line 42)

This limits minting to 2^64-1 per transaction while burning can handle up to 2^128-1. As a previous reviewer noted, this should be tracked as a GitHub issue rather than left as a code comment.

Based on past review comments, please create a GitHub issue to track this compilation limitation and document the workaround rationale. Consider whether this constraint is acceptable for the contract's intended use cases.

.gitmodules (1)

1-3: Make sure CI and local setup initialize the compact-tools submodule correctly

The submodule entry itself looks fine. Just ensure:

  • GitHub Actions (or other CI) use actions/checkout with submodules enabled (or equivalent) so installs don’t fail when @openzeppelin/compact-tools-* are resolved from ../compact-tools/....
  • CONTRIBUTING / README clearly mention git submodule update --init --recursive (or similar) so contributors don’t hit missing-tooling errors.
contracts/src/access/witnesses/interface.ts (1)

2-5: Revisit Ledger type source (mock artifact) and resolve TODO

The Ledger type is still imported from the mock contract artifact, and the TODO highlights uncertainty about this pattern. Given the earlier discussion on potential mismatches between mock‑exported ledger vars and the full on‑chain ledger surface, it would be good to either (a) switch to a canonical Ledger type from the interface artifact (if now available) or (b) clearly document why the mock artifact is the single source of truth and how you ensure it stays in sync.

🧹 Nitpick comments (7)
contracts/src/shielded-token/ShieldedFungibleToken.compact (1)

16-16: Consider the implications of hardcoded decimals.

The decimals value is hardcoded to 18, which matches the Ethereum standard but prevents creating tokens with different decimal precision. If all tokens in this system should always use 18 decimals, this is fine. Otherwise, consider making it a constructor parameter.

If flexibility is desired, apply this diff:

-constructor(nonce_: Bytes<32>,
-            name_: Opaque<"string">,
-            symbol_: Opaque<"string">,
-            domain_: Bytes<32>) {
-  const decimals = 18;
+constructor(nonce_: Bytes<32>,
+            name_: Opaque<"string">,
+            symbol_: Opaque<"string">,
+            decimals_: Uint<8>,
+            domain_: Bytes<32>) {
+  const decimals = decimals_;
   ShieldedFungibleToken_initialize(nonce_, name_, symbol_, decimals, domain_);
 }
contracts/package.json (1)

23-39: clean script is repo‑wide and potentially destructive; consider narrowing its scope

"clean": "git clean -fXd" will operate from the contracts directory but still target the whole git repo. That’s powerful and can wipe any ignored artifacts across the monorepo, not just contracts outputs.

If you want a safer contracts-only clean, consider scoping it to known build artifacts (e.g. rm -rf dist .turbo node_modules) or documenting clearly that this is a repo‑wide clean to avoid surprises.

package.json (1)

9-27: Align all compact:* scripts to explicitly target the contracts package

The updated scripts correctly filter build/test/types to ./contracts, and compact now scopes to @openzeppelin/midnight-apps-contracts, which matches the new workspace layout.

To keep behavior explicit and future‑proof, consider adding the same filter to the other compact:* scripts so they can’t accidentally fan out if another package ever defines a compact task:

-    "compact:fast": "turbo run compact -- --skip-zk",
-    "compact:version": "turbo run compact -- --version",
-    "compact:language-version": "turbo run compact -- --language-version",
+    "compact:fast": "turbo run compact --filter=@openzeppelin/midnight-apps-contracts -- --skip-zk",
+    "compact:version": "turbo run compact --filter=@openzeppelin/midnight-apps-contracts -- --version",
+    "compact:language-version": "turbo run compact --filter=@openzeppelin/midnight-apps-contracts -- --language-version",
contracts/src/math/witnesses/Field254.ts (1)

42-86: Consider extracting U256 conversion helpers.

The bigint-to-U256 conversion logic (splitting into 64-bit chunks) is duplicated in divUint254Locally, divU256Locally, and similar functions across Bytes32.ts and Uint128.ts. Consider extracting this into a shared utility (e.g., in u256.ts which already has toU256/fromU256).

This could be addressed in a follow-up PR since the current focus is file structure refactoring.

Also applies to: 118-174

contracts/src/access/types/ledger.ts (1)

9-13: Type re‑exports are correct; JSDoc is slightly outdated

Re‑exporting Ledger from the AccessControl artifact and Role from the Index artifact is the right way to keep TS types in sync with generated contracts. The descriptive comment about renaming AccessControl_RoleAccessControlRole no longer matches the actual exported names; consider updating it to mention Role instead.

contracts/src/access/witnesses/AccessControlWitnesses.ts (1)

3-5: Avoid depending on test utilities (emptyMerkleTreePath) in witness implementation

The imports overall look fine, but pulling emptyMerkleTreePath from ../utils/test.js couples production witness code to a test‑oriented module. That can make packaging/bundling harder and blurs the test vs runtime boundary. Consider moving emptyMerkleTreePath into a non‑test utility module (or inlining a minimal constant) and importing from there instead.

Also applies to: 9-13

contracts/src/access/test/accessControl.test.ts (1)

22-23: Consider narrowing the describe.skip to pathForLeaf‑dependent tests

Skipping the entire AccessControl suite because of the pathForLeaf issue significantly reduces coverage, including tests that don’t depend on Merkle paths (e.g., initialization and basic grantRole behavior). It would be better to either isolate the pathForLeaf/hasRole cases into a separate skipped block or gate those specific tests, and keep the rest running, while tracking the underlying bug in an issue.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a40570 and 101342d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (90)
  • .gitmodules (1 hunks)
  • compact-tools (1 hunks)
  • contracts/access/package.json (0 hunks)
  • contracts/access/src/Index.compact (0 hunks)
  • contracts/access/tsconfig.build.json (0 hunks)
  • contracts/access/tsconfig.json (0 hunks)
  • contracts/access/vitest.config.ts (0 hunks)
  • contracts/compact-std/.lintstagedrc.json (0 hunks)
  • contracts/compact-std/biome.json (0 hunks)
  • contracts/compact-std/package.json (0 hunks)
  • contracts/compact-std/tsconfig.build.json (0 hunks)
  • contracts/compact-std/tsconfig.json (0 hunks)
  • contracts/compact-std/vitest.config.ts (0 hunks)
  • contracts/math/.lintstagedrc.json (0 hunks)
  • contracts/math/biome.json (0 hunks)
  • contracts/math/package.json (0 hunks)
  • contracts/math/tsconfig.build.json (0 hunks)
  • contracts/math/tsconfig.json (0 hunks)
  • contracts/math/vitest.config.ts (0 hunks)
  • contracts/package.json (1 hunks)
  • contracts/shielded-token/.lintstagedrc.json (0 hunks)
  • contracts/shielded-token/README.md (0 hunks)
  • contracts/shielded-token/biome.json (0 hunks)
  • contracts/shielded-token/package.json (0 hunks)
  • contracts/shielded-token/src/ShieldedFungibleToken.compact (0 hunks)
  • contracts/shielded-token/src/types/index.ts (0 hunks)
  • contracts/shielded-token/tsconfig.build.json (0 hunks)
  • contracts/shielded-token/tsconfig.json (0 hunks)
  • contracts/src/access/AccessControl.compact (5 hunks)
  • contracts/src/access/Index.compact (1 hunks)
  • contracts/src/access/index.ts (1 hunks)
  • contracts/src/access/interfaces/IAccessControl.compact (1 hunks)
  • contracts/src/access/test/AccessControl.mock.compact (2 hunks)
  • contracts/src/access/test/AccessControlSimulator.ts (3 hunks)
  • contracts/src/access/test/accessControl.test.ts (10 hunks)
  • contracts/src/access/types/ledger.ts (1 hunks)
  • contracts/src/access/types/role.ts (1 hunks)
  • contracts/src/access/utils/compactHelper.ts (1 hunks)
  • contracts/src/access/utils/test.ts (1 hunks)
  • contracts/src/access/witnesses/AccessControlWitnesses.ts (8 hunks)
  • contracts/src/access/witnesses/interface.ts (4 hunks)
  • contracts/src/math/index.ts (1 hunks)
  • contracts/src/math/test/Bytes32.test.ts (1 hunks)
  • contracts/src/math/test/Bytes32Simulator.ts (1 hunks)
  • contracts/src/math/test/Field254.test.ts (1 hunks)
  • contracts/src/math/test/Field254Simulator.ts (1 hunks)
  • contracts/src/math/test/Max.test.ts (1 hunks)
  • contracts/src/math/test/MaxSimulator.ts (1 hunks)
  • contracts/src/math/test/Uint128.test.ts (1 hunks)
  • contracts/src/math/test/Uint128Simulator.ts (1 hunks)
  • contracts/src/math/test/Uint256.test.ts (1 hunks)
  • contracts/src/math/test/Uint256Simulator.ts (1 hunks)
  • contracts/src/math/test/Uint64.test.ts (1 hunks)
  • contracts/src/math/test/Uint64Simulator.ts (1 hunks)
  • contracts/src/math/utils/consts.test.ts (1 hunks)
  • contracts/src/math/utils/sqrtBigint.test.ts (1 hunks)
  • contracts/src/math/utils/u256.test.ts (1 hunks)
  • contracts/src/math/utils/u256.ts (1 hunks)
  • contracts/src/math/witnesses/Bytes32.ts (1 hunks)
  • contracts/src/math/witnesses/Field254.ts (1 hunks)
  • contracts/src/math/witnesses/Uint128.ts (1 hunks)
  • contracts/src/math/witnesses/Uint256.ts (1 hunks)
  • contracts/src/math/witnesses/Uint64.ts (1 hunks)
  • contracts/src/math/witnesses/interfaces.ts (1 hunks)
  • contracts/src/shielded-token/ShieldedFungibleToken.compact (1 hunks)
  • contracts/src/shielded-token/index.ts (1 hunks)
  • contracts/src/shielded-token/openzeppelin/ShieldedERC20.compact (4 hunks)
  • contracts/src/shielded-token/openzeppelin/Utils.compact (3 hunks)
  • contracts/src/shielded-token/test/ShieldedFungibleToken.test.ts (1 hunks)
  • contracts/src/shielded-token/test/ShieldedFungibleTokenSimulator.ts (1 hunks)
  • contracts/src/shielded-token/types/index.ts (1 hunks)
  • contracts/src/shielded-token/witnesses/index.ts (1 hunks)
  • contracts/src/structs/index.ts (1 hunks)
  • contracts/src/structs/test/QueueContractSimulator.ts (1 hunks)
  • contracts/src/structs/test/queueContract.test.ts (1 hunks)
  • contracts/src/structs/utils/test.ts (1 hunks)
  • contracts/src/structs/witnesses/QueueWitnesses.ts (1 hunks)
  • contracts/src/types/StandardLibrary.test.ts (1 hunks)
  • contracts/src/types/StandardLibrary.ts (1 hunks)
  • contracts/structs/.lintstagedrc.json (0 hunks)
  • contracts/structs/biome.json (0 hunks)
  • contracts/structs/package.json (0 hunks)
  • contracts/structs/tsconfig.build.json (0 hunks)
  • contracts/structs/tsconfig.json (0 hunks)
  • contracts/structs/vitest.config.ts (0 hunks)
  • contracts/tsconfig.build.json (1 hunks)
  • contracts/tsconfig.json (1 hunks)
  • contracts/vitest.config.ts (1 hunks)
  • package.json (1 hunks)
  • pnpm-workspace.yaml (1 hunks)
💤 Files with no reviewable changes (31)
  • contracts/compact-std/biome.json
  • contracts/access/vitest.config.ts
  • contracts/shielded-token/src/types/index.ts
  • contracts/shielded-token/README.md
  • contracts/shielded-token/package.json
  • contracts/compact-std/package.json
  • contracts/structs/vitest.config.ts
  • contracts/math/vitest.config.ts
  • contracts/structs/.lintstagedrc.json
  • contracts/access/package.json
  • contracts/compact-std/tsconfig.json
  • contracts/shielded-token/tsconfig.json
  • contracts/structs/biome.json
  • contracts/math/tsconfig.build.json
  • contracts/structs/tsconfig.json
  • contracts/shielded-token/src/ShieldedFungibleToken.compact
  • contracts/math/package.json
  • contracts/shielded-token/tsconfig.build.json
  • contracts/structs/tsconfig.build.json
  • contracts/compact-std/.lintstagedrc.json
  • contracts/access/tsconfig.json
  • contracts/math/tsconfig.json
  • contracts/shielded-token/.lintstagedrc.json
  • contracts/math/biome.json
  • contracts/access/tsconfig.build.json
  • contracts/access/src/Index.compact
  • contracts/compact-std/tsconfig.build.json
  • contracts/structs/package.json
  • contracts/math/.lintstagedrc.json
  • contracts/shielded-token/biome.json
  • contracts/compact-std/vitest.config.ts
🧰 Additional context used
🧬 Code graph analysis (5)
contracts/src/access/test/AccessControlSimulator.ts (2)
contracts/src/shielded-token/index.ts (1)
  • ledger (12-12)
contracts/src/access/index.ts (1)
  • Role (16-16)
contracts/src/access/witnesses/interface.ts (1)
contracts/src/access/index.ts (2)
  • Ledger (17-17)
  • Role (16-16)
contracts/src/access/witnesses/AccessControlWitnesses.ts (3)
contracts/src/access/index.ts (3)
  • AccessContractPrivateState (9-9)
  • Role (16-16)
  • Ledger (17-17)
contracts/src/types/StandardLibrary.ts (1)
  • ZswapCoinPublicKey (16-16)
contracts/src/access/utils/compactHelper.ts (1)
  • maybeFromNullable (11-24)
contracts/src/access/test/accessControl.test.ts (1)
contracts/src/access/types/role.ts (1)
  • RoleValue (7-19)
contracts/src/access/types/role.ts (1)
contracts/src/access/index.ts (2)
  • RoleValue (20-20)
  • Role (16-16)
🪛 GitHub Actions: Apps
compact-tools

[error] 1-1: ENOENT: no such file or directory, scandir '/home/runner/work/midnight-apps/midnight-apps/compact-tools/packages/cli'. Build process failed during npm run build with exit code 254.

🪛 GitHub Actions: Checks
compact-tools

[error] 1-1: ENOENT: no such file or directory, scandir '/home/runner/work/midnight-apps/midnight-apps/compact-tools/packages/cli'. The build failed during 'npm run build' in package 'compact'.

🪛 GitHub Actions: Contracts
compact-tools

[error] 1-1: ENOENT: no such file or directory, scandir '/home/runner/work/midnight-apps/midnight-apps/compact-tools/packages/cli'. This occurred during 'npm run build' in the 'packages/compact' workspace, causing the pipeline to fail with exit code 254.

⏰ 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: semgrep-cloud-platform/scan
🔇 Additional comments (60)
contracts/src/shielded-token/openzeppelin/Utils.compact (1)

17-19: Formatting and style adjustments align with refactoring objectives.

The indentation and spacing adjustments normalize code style across the file—particularly the consistent spacing before type constructors (e.g., ContractAddress { } instead of ContractAddress{ }). These changes introduce no functional impact and align with the goal of following the compact-contracts file structure.

Also applies to: 29-29, 76-76, 84-84

contracts/src/shielded-token/openzeppelin/ShieldedERC20.compact (1)

37-37: > Likely an incorrect or invalid review comment.

contracts/src/shielded-token/ShieldedFungibleToken.compact (3)

1-8: LGTM! Clean contract structure.

The license header, pragma, and imports are well-structured. The use of the prefix mechanism for importing ShieldedERC20 enables clean delegation to the underlying implementation.


20-38: LGTM! Clean delegation pattern.

The getter circuits properly delegate to the underlying implementation. The use of Uint<128> for totalSupply is appropriate for representing large token quantities.


40-46: Type difference between mint and burn is intentional design; access control is explicitly absent and documented.

The Uint<64> parameter in mint vs Uint<128> in burn is deliberate: the mint function accepts amounts up to 2^64 - 1, but internally casts to Uint<128> when updating _totalSupply. This allows individual mint operations to be size-limited while supporting larger accumulated burn operations. No fix needed here.

However, the documented caveat applies: the ShieldedERC20 module is marked "DO NOT USE IN PRODUCTION" and explicitly states that both mint and burn circuits include no access control, meaning anyone can call them. This is a known limitation of the current implementation documented in the module header.

contracts/src/shielded-token/test/ShieldedFungibleTokenSimulator.ts (2)

21-22: All import paths resolve correctly and the necessary exports are present.

  • ../../types/StandardLibrary.jscontracts/src/types/StandardLibrary.ts contains all imported types (CoinInfo, ContractAddress, Either, ZswapCoinPublicKey)
  • ../types/test.jscontracts/src/shielded-token/types/test.ts exports IContractSimulator
  • ../witnesses.jscontracts/src/shielded-token/witnesses/index.ts exports ShieldedFungibleTokenPrivateState and ShieldedFungibleTokenWitnesses

11-15: The artifact import path ../../../artifacts/shielded-token/ShieldedFungibleToken/contract/index.cjs is correctly structured for accessing generated Compact compiler artifacts. This relative path from the test directory to the generated artifacts root is standard practice and not a source of complexity or errors. Artifact generation is part of the normal build pipeline orchestrated by Turbo.

Likely an incorrect or invalid review comment.

contracts/tsconfig.json (1)

7-16: Add explicit moduleResolution option.

The configuration does not explicitly specify moduleResolution, which will be inherited from @tsconfig/node24/tsconfig.json. Since the AI summary indicates the project uses explicit .js file extensions for ES module format, you should explicitly set moduleResolution to match Node's actual module resolution behavior. Based on the past review feedback, this should be clarified rather than implicitly inherited.

Please verify the appropriate moduleResolution value:

  • Use "nodenext" for modern Node.js ESM support with explicit extensions
  • Or use "bundler" depending on your tooling requirements
       "isolatedModules": true,
       "resolveJsonModule": true,
+      "moduleResolution": "nodenext"
     }

You can verify this matches your module import patterns by checking the documentation for TypeScript moduleResolution.

contracts/tsconfig.build.json (1)

1-5: LGTM!

The build configuration properly extends the base config and correctly excludes test files for the build output. Clean and well-structured.

contracts/src/shielded-token/witnesses/index.ts (1)

1-2: Imports look consistent with the new artifacts layout and ESM style

The updated Ledger artifact path and the .js extension for EmptyState both look correct given a src/artifacts/ structure and ESM-friendly TS imports. Since this relies on your TS module resolution and declaration files lining up with index.cjs / state.js, just make sure a full tsc run passes after the refactor.

contracts/src/shielded-token/index.ts (1)

3-14: Artifact re‑export path is correct and consistently used throughout the codebase

The new ../../artifacts/shielded-token/ShieldedFungibleToken/contract/index.cjs path in the barrel export is correct and matches the relative path expectations from contracts/src/shielded-token/. No remaining old artifact paths exist in the codebase—all references already use the centralized artifact location consistently.

pnpm-workspace.yaml (1)

1-4: Workspace scope update for contracts looks consistent

Switching to a single contracts workspace package matches the new monolithic contracts/package.json and the updated Turbo filters. No issues from what’s visible here.

contracts/package.json (1)

41-58: Confirm compact-tools paths and CI behavior for local file: devDependencies

Using local file: links to the compact-tools submodule from here:

"@openzeppelin/compact-tools-cli": "file:../compact-tools/packages/cli",
"@openzeppelin/compact-tools-simulator": "file:../compact-tools/packages/simulator"

is reasonable and matches the .gitmodules layout. Just make sure that:

  • CI is cloning submodules before pnpm install, otherwise these paths will fail resolution.
  • Local dev instructions clearly mention initializing the submodule so pnpm can see these packages.

Everything else in the dependencies block looks coherent with the new structure.

contracts/vitest.config.ts (1)

3-9: Verbose reporter addition looks fine

Using reporters: 'verbose' under test should just increase per‑test output without affecting which tests run (include is still restricted to src/**/*.test.ts). No issues from what’s shown.

contracts/src/math/utils/consts.test.ts (1)

1-9: LGTM!

The import path update to use explicit .js extension aligns with ES module resolution requirements. The test logic remains unchanged and correctly validates all MAX_UINT* constants.

contracts/src/access/utils/test.ts (1)

10-10: LGTM!

The import path update to include the explicit .js extension is consistent with the ES module migration across the codebase.

contracts/src/math/utils/u256.test.ts (1)

1-3: LGTM!

Import paths updated consistently with the ES module migration. The test suite provides comprehensive coverage including edge cases and round-trip conversions.

contracts/src/math/witnesses/Bytes32.ts (1)

1-7: LGTM!

Import paths consistently updated to match the new artifact structure. The witness implementations correctly handle U256 conversions.

contracts/src/math/witnesses/Field254.ts (1)

1-9: LGTM!

Import paths consistently updated to the new artifact structure with appropriate extensions (.d.cts, .cjs, .js).

contracts/src/math/witnesses/Uint128.ts (1)

1-9: Artifact imports are correctly structured for generated files.

The imports reference generated artifact files from artifacts/math/Index/contract/index.d.cts and artifacts/math/test/Uint128.mock/contract/index.cjs, which are properly gitignored. The .d.cts extension for type declarations and .cjs extension for the CommonJS mock Ledger are appropriate for their respective module systems.

contracts/src/math/utils/u256.ts (1)

1-2: Imports follow the codebase convention; artifact path verification deferred to post-build.

Both imports are correct. The .js extension pattern in TypeScript source files is consistent across the codebase with "type": "module" in package.json. The artifact path ../../../artifacts/math/Index/contract/index.d.cts cannot be verified in the pre-build state, but the import structure is sound and will resolve correctly after the build process generates the artifact files.

contracts/src/math/test/Uint64.test.ts (1)

2-6: LGTM! Import paths updated for ES module resolution.

The explicit .js extensions align with ES module conventions and are consistent with the PR's refactoring objectives. No logic changes detected.

contracts/src/math/witnesses/interfaces.ts (1)

9-9: LGTM! Artifact path updated for new directory structure.

The import path now correctly references the restructured artifact location (../../../artifacts/math/...) and uses the .d.cts extension for CommonJS type declarations. This aligns with the PR's goal of following the compact-contracts structure.

contracts/src/math/test/Max.test.ts (1)

2-2: LGTM! Import path updated for ES module resolution.

The explicit .js extension is consistent with the repository-wide migration to ES module conventions.

contracts/src/math/test/Field254.test.ts (1)

2-3: LGTM! Import paths updated for ES module resolution.

Both utility and simulator imports now use explicit .js extensions, consistent with the PR's ES module migration.

contracts/src/math/test/Bytes32.test.ts (1)

2-2: LGTM! Import path updated for ES module resolution.

The explicit .js extension maintains consistency with the repository-wide ES module adoption.

contracts/src/math/utils/sqrtBigint.test.ts (1)

2-2: LGTM! Import path updated for ES module resolution.

The utility import now uses the explicit .js extension, aligning with ES module conventions.

contracts/src/structs/witnesses/QueueWitnesses.ts (1)

1-1: LGTM! Type import path updated for ES module resolution.

The type import now uses the explicit .js extension, consistent with the ES module migration across the codebase.

contracts/src/structs/test/queueContract.test.ts (1)

3-3: LGTM! Import path updated for ES module resolution.

The simulator import now uses the explicit .js extension, maintaining consistency with the repository-wide ES module adoption.

contracts/src/math/test/Uint256.test.ts (1)

10-14: LGTM! ES module import paths updated correctly.

The addition of .js extensions to import paths aligns with ES module standards and is consistent with the broader refactoring across the codebase.

contracts/src/types/StandardLibrary.test.ts (1)

14-14: LGTM! More explicit import path.

The change from './index' to './StandardLibrary.js' makes the import more explicit and aligns with ES module conventions.

contracts/src/structs/utils/test.ts (1)

7-7: LGTM! ES module import updated correctly.

contracts/src/math/test/Uint128.test.ts (1)

9-13: LGTM! Consistent ES module import updates.

contracts/src/structs/index.ts (1)

10-10: LGTM! Export path updated for ES modules.

contracts/src/shielded-token/types/index.ts (1)

1-2: LGTM! New type exports added.

This new barrel export file expands the public API surface by exposing IContractSimulator and EmptyState types, which aligns with the refactoring goals.

contracts/src/access/utils/compactHelper.ts (1)

1-1: All three migration requirements are satisfied.

The Maybe type is properly exported from the local StandardLibrary.ts module (confirmed by both the export and passing test), no remaining imports from @openzeppelin/midnight-apps-compact-std exist in the codebase, and the external package has been removed from package.json dependencies. The migration from the external package to the local module is complete and consistent.

contracts/src/math/witnesses/Uint64.ts (1)

2-6: Artifact import paths are correctly configured and will be generated by the build process.

The relative import paths from contracts/src/math/witnesses/Uint64.ts correctly resolve to contracts/artifacts/math/..., which is generated during the build process. The build:contracts task explicitly handles "artifact copying" after the compact task compiles .compact files. The explicit file extensions (.d.cts for TypeScript definitions and .cjs for CommonJS modules) are appropriate and consistent across all witness implementations (Uint64, Uint128, Uint256, Bytes32, Field254, and interfaces).

contracts/src/access/Index.compact (1)

6-23: Barrel export for access ledger state looks consistent

The module-level docs and the re-export list (Role, isInitialized, roleCommits, roleNullifiers, index) line up with what you’d expect from IAccessControl and provide a clean, centralized surface; no issues spotted in the structure of this index module.

contracts/src/types/StandardLibrary.ts (1)

6-18: Stdlib type re-export path change preserves public API

The switch to ../../artifacts/types/Std/contract/index.cjs keeps the exported type set (Maybe, Either, CurvePoint, MerkleTree*, ContractAddress, CoinInfo, QualifiedCoinInfo, ZswapCoinPublicKey, SendResult) intact, so callers see a stable API with only the underlying source moved. No further changes needed here.

contracts/src/math/test/Bytes32Simulator.ts (1)

13-18: Bytes32 simulator imports align with new artifacts layout

The updated mock contract, simulator type, and witness imports (including .js extensions) are consistent with the rest of the math test suite and do not change runtime behavior. Looks good.

contracts/src/math/witnesses/Uint256.ts (1)

1-11: Uint256 witness imports now point at the math index and test artifacts

The new import paths for DivResultU128/DivResultU256/U128/U256, Ledger, EmptyState, sqrtBigint, and IUint256Witnesses are consistent with the reorganized math artifacts and local helper layout. The witness factory and arithmetic logic remain unchanged, so behavior should be preserved.

contracts/src/math/test/Uint256Simulator.ts (1)

12-23: Uint256 simulator imports correctly track new math artifacts and witnesses

The updated imports for DivResultU128/DivResultU256/U256, the Uint256 mock contract, simulator type, and Uint256Witnesses (with .js extension) are consistent with the math refactor and keep the simulator’s behavior intact. No further changes needed here.

contracts/src/math/test/Uint128Simulator.ts (1)

12-23: Uint128 simulator now targets the shared math index and test artifacts

The new type and mock contract imports, plus the .js extensions for the simulator types and witnesses, are aligned with the updated math layout and other simulators. Public surface and behavior remain unchanged.

contracts/src/math/test/Field254Simulator.ts (1)

12-25: Field254 simulator imports are consistent with the new math artifacts structure

The updated type, mock contract, simulator type, and witness imports (including .js extensions) match the patterns in the other math simulators and keep the simulator behavior the same. The malicious override wiring still looks correct.

contracts/src/structs/test/QueueContractSimulator.ts (1)

10-18: No action required—witness import and constructor usage are correct

QueueWitnesses is exported as a plain object (export const QueueWitnesses = {}), not a factory function. Passing it directly in the constructor (new MockQueue<QueueContractPrivateState>(QueueWitnesses)) is correct and matches the contract's expectations. This differs from the math witnesses pattern (Bytes32Witnesses, Uint256Witnesses) which are factory functions, but that's intentional—QueueWitnesses is a static object with no initialization logic required.

contracts/src/math/test/Uint64Simulator.ts (1)

12-19: Import path and .js extension updates look consistent

The updated artifact paths and .js extensions for DivResultU64, Contract/Ledger, IContractSimulator, and Uint64PrivateState/Uint64Witnesses all align with the new artifacts/math/... layout and ESM-style resolution. No behavioral changes introduced here.

contracts/src/access/types/role.ts (1)

1-19: RoleValue now tied to canonical Role and StandardLibrary types

Wiring role: Role and importing MerkleTreePath from StandardLibrary.js ensures this type stays in sync with the ledger/artifact definitions while remaining purely type-level. This is a straightforward and correct refactor.

contracts/src/access/interfaces/IAccessControl.compact (1)

1-42: IAccessControl interface cleanly centralizes Role and public ledgers

Role and the four exported ledgers match the access-control surface used elsewhere (mock, simulator, TS ledger types). The declarations look consistent with CompactStandardLibrary conventions and should generate coherent artifacts for the TS layer.

contracts/src/math/test/MaxSimulator.ts (1)

8-18: Max simulator imports correctly updated to artifacts and .js paths

Using the .d.cts artifact for U128/U256 types and the Max.mock CJS contract for Contract/Ledger, plus switching local imports to .js, is consistent with the rest of the math test suite and doesn’t alter runtime behavior.

contracts/src/access/test/AccessControlSimulator.ts (3)

11-23: Simulator imports now reference shared artifact/JS surfaces

Importing Role from the access Index artifact, Ledger/MockAccessControl from the test artifact, and switching StandardLibrary, simulator types, and witnesses to .js paths matches the new structure and keeps the simulator aligned with the generated artifacts.


79-81: Double‑check using originalState.data for public ledger decoding

Switching getCurrentPublicState to ledger(this.circuitContext.originalState.data) may change semantics compared to using transactionContext.state: if circuits only mutate transactionContext.state and leave originalState as the pre‑call snapshot, this will always return the initial ledger instead of the updated one.

Please confirm that originalState is indeed updated by MockAccessControl circuits; if not, consider retaining the previous transactionContext.state‑based call.


106-122: GrantRole now correctly uses the canonical Role enum

Updating grantRole to take role: Role ties the simulator directly to the new enum defined in the access artifacts/interface, keeping the test surface consistent with the mock (testGrantRole) and the Compact interface.

contracts/src/access/index.ts (1)

8-14: Barrel now targets compiled JS modules for witnesses and interfaces

Pointing AccessContractPrivateState/AccessControlWitnesses and IAccessControlWitnesses at their .js counterparts is consistent with the project‑wide ESM move and should keep the entrypoint usable from JS and TS without changing semantics.

contracts/src/access/test/AccessControl.mock.compact (2)

10-14: Mock now re‑exports state and Role from the shared interface

Importing IAccessControl and exporting roleCommits, isInitialized, index, and Role from here keeps the mock’s public surface aligned with the canonical interface while still exposing AccessControl_hashUserRole for tests. This is a good consolidation point for access‑control state in the test harness.


32-34: testGrantRole correctly updated to use the new Role type

The test circuit now accepts role: Role and forwards it to AccessControl_grantRole, matching the new enum defined in IAccessControl/artifacts. This keeps the mock and simulator signatures consistent.

contracts/src/access/witnesses/interface.ts (1)

20-25: wit_ witness interface looks consistent with the compact contract*

The wit_updateRole, wit_getRoleMerklePath, and wit_getSecretKey signatures (context + args → [P, …]) look coherent with the AccessControl.compact witness declarations and the TS implementation in AccessControlWitnesses.ts; I don't see issues here.

Also applies to: 33-36, 43-43

contracts/src/math/index.ts (1)

10-33: Math barrel exports updated cleanly to new module layout

The .js specifiers and added exports (sqrtBigint, IContractSimulator, EmptyState) keep this entrypoint aligned with the rest of the refactor without introducing behavior changes; looks good.

contracts/src/access/witnesses/AccessControlWitnesses.ts (1)

120-135: Witness implementations align with interface and compact contract semantics

The AccessControlWitnesses methods (wit_updateRole, wit_getRoleMerklePath, wit_getSecretKey) correctly wrap AccessContractPrivateState, operate on WitnessContext<Ledger, AccessContractPrivateState>, and return [privateState, …] as expected. The guard around missing roleEntry/index before calling roleCommits.pathForLeaf is also appropriate. No issues from my side here.

Also applies to: 143-168, 175-179

contracts/src/access/test/accessControl.test.ts (1)

7-11: Tests correctly track new Role and ledger/public‑state surface

The updated imports (artifact‑sourced Role, mock pureCircuits, .js simulator, and local RoleValue) and the expectations around isInitialized, roleCommits, index, and stored RoleValue.index all look consistent with the refactored AccessControl contract and private‑state helpers. The index assumptions (0n for the initial admin, then 2n after a single grant) and the count of role entries (3 for admin + Lp + Trader) align with the underlying _grantRole logic.

Also applies to: 30-38, 40-58, 63-82, 96-121, 124-141, 148-161, 166-199

contracts/src/access/AccessControl.compact (1)

14-37: AccessControl.compact witness wiring matches the new interface and TS layer

Importing ./interfaces/IAccessControl and exporting wit_updateRole, wit_getRoleMerklePath, and wit_getSecretKey brings the compact contract’s public witness surface in line with the shared interface and the TS witness implementation. The updated call sites in _grantRole, hasRole, and hashNullifier use these witnesses coherently, so the on‑chain circuit, ledger, and host‑side witnesses stay in sync.

Also applies to: 83-86, 169-170, 183-186

@0xisk 0xisk requested review from andrew-fleming and emnul December 9, 2025 14:33
@0xisk
Copy link
Member Author

0xisk commented Dec 9, 2025

This PR is depending on the hierarchical feature from this PR: OpenZeppelin/compact-tools#27

@0xisk
Copy link
Member Author

0xisk commented Dec 12, 2025

@andrew-fleming I am fixing some of the requested changes from #269 here because they were actually related to this PR. Also fixing still the failed workflows

Copy link
Contributor

@andrew-fleming andrew-fleming left a comment

Choose a reason for hiding this comment

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

Looking good, @0xisk! Left some comments

"extends": "./tsconfig.json",
"exclude": ["src/test/**/*.ts"],
"compilerOptions": {}
} 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.

Suggested change
}
}

Comment on lines 24 to 25
"compact": "compact-compiler",
"compact:fast": "compact-compiler --skip-zk",
Copy link
Contributor

Choose a reason for hiding this comment

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

The root turbo.json needs to change the compact outputs to this:

      "outputs": [
        "artifacts/**"
      ]

Copy link
Contributor

Choose a reason for hiding this comment

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

There's also type issues as well...not sure if that's meant to be handled in future PRs or if that should be resolved now

Copy link
Member Author

Choose a reason for hiding this comment

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

I think the types issue should be resolved now.

Comment on lines 9 to 12
* @typedef {Object} Ledger
*/
// biome-ignore lint/performance/noBarrelFile: entrypoint module
export {
Copy link
Contributor

Choose a reason for hiding this comment

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

Line 11: ⚠ Suppression comment has no effect. Remove the suppression or make sure you are suppressing the correct rule.

Copy link
Member Author

Choose a reason for hiding this comment

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

That file is deleted entirely

Copy link
Contributor

Choose a reason for hiding this comment

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

The submodules should be ignored for all relevant commands in this manifest

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think the scripts affect the submodules, could you confirm if they get affected on your side?

Comment on lines +96 to +97
"compact-tools/packages/cli/dist/runCompiler.js"
"compact-tools/packages/cli/dist/runBuilder.js"
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need both? Consider that build already includes compact in the turbo.json

@0xisk
Copy link
Member Author

0xisk commented Dec 16, 2025

@andrew-fleming, pushed huge improvements and changes, the main issue was that the Field254.compact was actually buggy as the MAX_FIELD was wrong, and as I started fixing that I through it is better to just upgrade all directly to 0.27.0-rc.1 Compact version and then have a one universal fixes.

Now, because of the Uint size limit breaking changes, I had to move many of the Math contracts to the archive as I will separably fix them in another issue. Also, I archived the std library as it also had a lot of changes and our version is very outdated, that will be included in that PR also.

Finally, had a lot of improvement to the existing code by using the Simulator pkg, and moving the witnesses into the test directory, clean any unneeded ts scripts.

Changes:

  • f37245e: Improve AccessControl by using the simulator and fix pathForLeaf.

  • b9888dc: Upgrade to v0.27.0-rc.1; archive Uint256, Field255, and Bytes32 due to breaking changes (follow-up PR needed).

  • cd3009d: Archive affected math libraries and std; types package requires a separate update.

  • c399c42: Upgrade shielded token contracts; remove types directory; move witnesses into tests.

  • 1b35022: Upgrade struct contracts; delete types and utils directories; move witnesses into tests.

  • 6faa6ee: Remove the outdated types package, deferring it to a separate PR.

  • 3f43313: Pin compact-contracts dependency to v0.0.1-alpha.1.

  • 6f6a5a7: Update the compact-runtime package to align with the refactored structure.

@0xisk
Copy link
Member Author

0xisk commented Dec 18, 2025

Important note

@andrew-fleming @emnul This PR is blocked by those two PRs: #274, #270
I then will rebase with this branch so the gh actions will be resolved. But there will be an issue is to manually install the 0.27.0-rc.1

@andrew-fleming
Copy link
Contributor

I then will rebase with this branch so the gh actions will be resolved. But there will be an issue is to manually install the 0.27.0-rc.1

IMO our time will be better spent pushing 0.27.0-rc.1 0.28.0 code to a non-main dedicated branch until there's a public release for the new version in order to avoid refactoring the CI twice. I think this makes life easier. LMK if you disagree

@0xisk
Copy link
Member Author

0xisk commented Dec 19, 2025

I then will rebase with this branch so the gh actions will be resolved. But there will be an issue is to manually install the 0.27.0-rc.1

IMO our time will be better spent pushing 0.27.0-rc.1 0.28.0 code to a non-main dedicated branch until there's a public release for the new version in order to avoid refactoring the CI twice. I think this makes life easier. LMK if you disagree

I agree with you 👍

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.

4 participants