Skip to content

feat: immutables macro#28

Merged
zkfrov merged 11 commits into
devfrom
feat/immutables-macro
Mar 6, 2026
Merged

feat: immutables macro#28
zkfrov merged 11 commits into
devfrom
feat/immutables-macro

Conversation

@zkfrov
Copy link
Copy Markdown
Collaborator

@zkfrov zkfrov commented Mar 3, 2026

🤖 Linear

Closes AZT-XXX

Description

This branch introduces the #[immutables] macro pattern for Aztec Noir contracts — a mechanism that allows contracts to store immutable values committed via the contract's salt, eliminating the need for
an initializer transaction. It includes the Noir library, example contracts, a full TypeScript SDK, tests, benchmarks, and CI infrastructure.

Noir Library & Contracts (PRs #8, #16, #19, #27)

  • #[immutables] comptime macro (src/nr/immutables/src/macro.nr) that generates:
    • Serialize / Deserialize implementations
    • Immutables::init(context) — loads from capsule and verifies against instance.salt
    • Immutables::init_unconstrained(context) — unconstrained load without verification
    • Salt derivation: salt = poseidon2_hash([actual_salt, ...serialized_immutables])
  • immutables_contract — Demo contract with both immutables and mutable storage (mixed usage)
  • schnorr_initializerless_account_contract — Account contract using the initializerless pattern (signing key committed via salt, no initializer needed)
  • schnorr_account_contract — Standard Schnorr account with initializer-based key storage (baseline for comparison)
  • Noir TXE test scaffolding (most tests disabled pending aztec-packages#16656 — TXE doesn't support custom salt)
  • Upgraded to Aztec v4.0.0-devnet.1-patch.0

TypeScript SDK (PR #9)

  • src/ts/immutables/ — Generic utilities for deploying any contract using #[immutables]:
    • computeContractSalt(actualSalt, serializedImmutables)
    • createImmutablesCapsule(address, actualSalt, fields)
    • deployWithImmutables(wallet, artifact, fields, options?)
    • Supports both published (on-chain) and unpublished (PXE-only) deployment
  • src/ts/schnorr-initializerless-account/ — Account contract integration:
    • SchnorrInitializerlessAccountContract (implements AccountContract interface)
    • SchnorrInitializerlessAuthWitnessProvider (Schnorr signature creation)
    • registerInitializerlessAccount(wallet, options?) — one-call deployment + wallet registration
    • computeSchnorrAccountAddress(signingKey, options?) — pre-compute address before deployment

Tests & Benchmarks (PR #9)

File Description
schnorr-initializerless-account.test.ts 12 tests: deploy + read key, different keys/salts → different addresses, wrong capsule/actualSalt rejection, published + unpublished variants
immutables-contract.test.ts Published/unpublished deploy, wrong capsule rejection, mixed usage with initializer
e2e.test.ts End-to-end with Dripper FPC: initializerless account receives private tokens, transfers, balance checks vs standard SchnorrAccount
account.benchmark.ts Benchmark suite for account contract operations

Documentation & CI (PRs #16, #19)

  • Full README rewrite with usage guide, how-it-works explanation, capsule documentation, and project structure
  • CI workflows for PR checks, pre-release publishing, and baseline tracking

Summary by CodeRabbit

  • New Features

    • Immutables macro and initializerless immutables deployment workflow; Schnorr account variants; TypeScript SDK for artifact introspection, serialization, address precomputation, and deploy helpers; new account benchmarks.
  • Documentation

    • README rewritten around immutables pattern, deployment/verification guides and examples.
  • Tests

    • Comprehensive end-to-end test suites for immutables and Schnorr account flows.
  • Chores

    • Removed legacy counter examples; CI/workflow reorganization; package rebranding; updated pre-commit formatter and expanded .gitignore.

zkfrov and others added 5 commits February 11, 2026 11:32
# 🤖 Linear

  Closes AZT-678

  # Description

Add initializerless constants pattern for Aztec Noir contracts. This
pattern allows contracts to store
immutable values committed via the contract's salt, eliminating the need
for an initializer transaction.

  ## Changes

  ### Initializerless Library (`src/nr/initializerless`)
  - `#[constants]` comptime macro that generates:
- `Serialize` / `Deserialize` implementations (via
`derive_serialize_if_not_implemented` /
  `derive_deserialize_if_not_implemented`)
- `Constants::init(context)` — loads from capsule and verifies against
`instance.salt`
- `Constants::init_unconstrained(context)` — unconstrained load without
verification
- Salt derivation: `salt = poseidon2_hash([actual_salt,
...serialized_constants])`
- Deterministic `CONSTANTS_SLOT` computed from
`poseidon2_hash_bytes("CONSTANTS_SLOT")`

  ### New Contracts
- **`constants_contract`** — Demo contract with both constants and
mutable storage, showcasing mixed
  usage
- **`schnorr_constants_account_contract`** — Account contract using the
initializerless pattern (signing
   key committed via salt, no initializer needed)
- **`schnorr_account_contract`** — Standard Schnorr account with
initializer-based key storage (used as
  baseline for comparison in tests/benchmarks)

  ### Infrastructure
  - Upgrade to Aztec `v4.0.0-nightly.20260204`
  - CI workflow updates for test runner
# Description

  - Rename macro library: `initializerless` → `constants`
  - Rename macro file: `constants.nr` → `macro.nr`
- Rename contract: `schnorr_constants_account_contract` →
`schnorr_initializerless_account_contract`
- Update all `Nargo.toml` dependencies and workspace members to match
new names
- Update all `use initializerless::constants` → `use
constants::constants` across contracts
- Rewrite README with full usage guide, how-it-works explanation, and
project structure

---------

Signed-off-by: frov <frov@wonderland.xyz>
# Description

- Renamed constants → immutables across the entire codebase: Noir
libraries, contracts, directory names, file names, artifacts, config
files, and README
- Added capsule usage documentation (Section 4 in README) showing how to
attach capsules to transactions
- Bumped aztec dependency from v4.0.0-nightly.20260204 to
v4.0.0-devnet.1-patch.0 (Nargo.toml + package.json)
  - Fixed breaking changes from the version bump:
    - #[nophasecheck] → #[allow_phase_change] (renamed in aztec-nr)
- use dep::aztec:: → use aztec:: (Noir compiler dropped the dep::
prefix)

---------

Signed-off-by: frov <frov@wonderland.xyz>
Co-authored-by: Paperclip Minimizer <minim@wonderland.xyz>
…ests and benchmarks (#9)

# 🤖 Linear

Closes AZT-707

- Add comprehensive TypeScript test suite (E2E, unit, integration) for
the `#[immutables]` macro pattern
- Add TypeScript utilities for deploying contracts with immutables (salt
computation, capsule creation, PXE registration)
- Add `SchnorrInitializerlessAccountContract` TypeScript integration
(AccountContract impl, AuthWitnessProvider, wallet registration)
  - Add standard `SchnorrAccount` utilities for comparison testing
  - Add CI workflow for building `aztec-standards` artifacts
- Remove duplicate Noir contracts (`initializerless/`,
`schnorr_immutables_account_contract/`) consolidated in
`feat/constant-account`
- Update README with TypeScript utilities docs, published vs unpublished
deployment, and `#[noinitcheck]` explanation

  ## Details

  ### TypeScript Utilities (`src/ts/immutables/utils.ts`)

Generic module for deploying **any** contract using the `#[immutables]`
macro:
- `computeContractSalt(actualSalt, serializedImmutables)` — derives salt
via `poseidon2Hash`
- `createImmutablesCapsule(address, actualSalt, fields)` — creates
capsule for function calls
- `deployWithImmutables(wallet, artifact, fields, options?)` — full
deployment: instance creation, PXE registration, class + instance
publication
- Supports both published (on-chain) and unpublished (PXE-only)
deployment via `skipInstancePublication`

### Account Contract Integration
(`src/ts/schnorr-initializerless-account/`)

- `SchnorrInitializerlessAccountContract` — implements `AccountContract`
interface (no initializer, salt-based key verification)
- `SchnorrInitializerlessAuthWitnessProvider` — Schnorr signature
creation for tx authorization
- `registerInitializerlessAccount(wallet, options?)` — one-call
deployment + wallet registration with key derivation
- `computeSchnorrAccountAddress(signingKey, options?)` — pre-compute
address before deployment

  ### Tests

  | File | Description | Tests |
  |------|-------------|-------|
| `schnorr-initializerless-account.test.ts` | Immutables pattern for
account contracts | 12 tests: deploy + read key, different keys/salts →
different addresses, wrong capsule/actualSalt rejection, published +
  unpublished variants |
| `immutables-contract.test.ts` | Immutables + storage coexistence |
Published/unpublished deploy, wrong capsule rejection, mixed usage with
initializer |
| `e2e.test.ts` | End-to-end with Dripper FPC | Initializerless account
receives private tokens via drip, transfers, balance checks — compared
against standard SchnorrAccount |

  ### CI

- `scripts/build-aztec-standards.ts` — builds external `aztec-standards`
token/dripper artifacts needed for E2E tests
  - Updated `tests.yml` workflow to run build step before tests

  ### Noir cleanup

  Removed duplicate contracts that were consolidated in the base branch:
  - `src/nr/initializerless/` (duplicate of `src/nr/immutables/`)
- `src/nr/schnorr_immutables_account_contract/` (duplicate of
`src/nr/schnorr_initializerless_account_contract/`)
<!--start_gitstream_placeholder-->
### ✨ PR Description
Purpose: Add comprehensive production infrastructure for initializerless
immutables pattern with TypeScript SDK, benchmarks, and automated
deployment workflows.

Main changes:
- Implemented persistent CapsuleStore integration with
`store_immutables` utility and artifact introspection via
`#[abi(immutables)]` layout generation
- Added complete TypeScript SDK with `deployWithImmutables`,
`serializeFromLayout`, and account contract integration for
SchnorrInitializerlessAccount
- Configured CI/CD pipelines for PR benchmarks, pre-release publishing,
and baseline tracking with aztec-benchmark integration

_Generated by LinearB AI and added by gitStream._
<sub>AI-generated content may contain inaccuracies. Please verify before
using.
💡 **Tip:** You can customize your AI Description using **Guidelines**
[Learn
how](https://docs.gitstream.cm/automation-actions/#describe-changes)</sub>
<!--end_gitstream_placeholder-->

---------

Signed-off-by: frov <frov@wonderland.xyz>
Co-authored-by: Weißer Hase <84595958+wei3erHase@users.noreply.github.com>
Co-authored-by: Weißer Hase <wei3erHase@protonmail.com>
# Description
- Add Noir TXE test scaffolding for `immutables_contract` and
`schnorr_initializerless_account_contract`
- Most tests are disabled because the TXE does not support deploying
contracts with a custom salt
([aztec-packages#16656](AztecProtocol/aztec-packages#16656)),
which is required for `Immutables::init()` salt verification
- One storage-only test (`increment_counter_success`) runs successfully
since it doesn't depend on salt verification
  - Update README with test directory structure and TXE limitation note
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 3, 2026

Caution

Review failed

Failed to post review comments

Walkthrough

Adds an immutables Noir macro, initializerless Schnorr account and supporting Noir contracts, TypeScript immutables/account tooling and E2E tests, replaces counter benchmarks/tests with account-focused suites, updates package metadata and CI to reusable workflows, and removes sandbox/version-check scripts and some in-repo workflows.

Changes

Cohort / File(s) Summary
Code review config
\.coderabbit\.yaml
New CodeRabbit configuration added for automated reviews, path-based guidance, tooling, and chat/KB integrations.
CI workflows
.github/workflows/...
\compare-benchmark.yml`, `lint.yml`, `tests.yml`removed;`main-tests.yml`, `pr-checks.yml`, `pre-release.yml`, `publish.yml`, `update-baseline.yml`` added/changed
Removed several in-repo workflows (lint, tests, compare-benchmark) and added reusable-workflow driven CI (tests, PR checks, publish, pre-release, baseline updates).
Repo metadata & packaging
package.json, README.md, .gitignore, tsconfig.json, tsconfig.build.json
Package renamed/republished as @defi-wonderland/aztec-immutables-macro, exports and publishConfig added, README rewritten for immutables pattern, .gitignore broadened, TS build config added, tsconfig include tightened.
Pre-commit hook
.husky/pre-commit
Formatter changed from aztec fmt to nargo fmt.
Removed dev scripts & setup
scripts/check-aztec-version.ts, scripts/start-sandbox.ts, vitest.setup.ts
Deleted Aztec CLI version checker, sandbox manager, and Vitest global setup/teardown.
Noir immutables macro
src/nr/immutables/...
Nargo.toml, src/lib.nr, src/macro.nr
New Noir library exposing immutables macro that emits layout globals, derives/ensures Deserialize, generates init/init_unconstrained/store, and produces capsule layout metadata for tooling.
Immutables contract & tests
src/nr/immutables_contract/...
Nargo.toml, src/main.nr, src/test.*, src/test/utils.nr
New ImmutablesContract demonstrating initializerless pattern, mixed storage+immutables usage, store/init flows, and test scaffolding (some tests disabled due to TXE salt limitations).
Schnorr account contracts
src/nr/schnorr_account_contract/..., src/nr/schnorr_initializerless_account_contract/...
Added standard Schnorr account and initializerless Schnorr account (uses immutables), plus public-key note/types and test scaffolding.
Removed counter NR & tests
src/nr/counter_contract/...
Removed Counter contract, tests, and utilities.
Benchmarks
benchmarks/counter.benchmark.ts removed, benchmarks/account.benchmark.ts added, Nargo.toml workspace updated
Replaced counter benchmark with account comparison benchmark (immutables vs standard Schnorr); updated Nargo workspace members.
TypeScript immutables & account tooling
src/ts/immutables/index.ts, src/ts/immutables-contract/utils.ts, src/ts/schnorr-initializerless-account/index.ts, src/ts/schnorr-account/utils.ts, src/ts/index.ts
New TS modules: artifact introspection, layout serialization, salt/capsule creation, precompute/deployWithImmutables flows, Schnorr account factories and auth-witness provider, and re-exports.
TypeScript tests & utilities
src/ts/counter.test.ts removed, src/ts/e2e.test.ts, src/ts/immutables-contract.test.ts, src/ts/schnorr-initializerless-account.test.ts, src/ts/immutables-contract/utils.ts, src/ts/utils.ts
Removed old counter E2E tests; added comprehensive E2E suites for immutables and initializerless accounts; updated test utilities (CustomEmbeddedWallet, setupTestSuite, sponsored FPC registration).
Vitest config
vitest.config.ts
Removed globalSetup reference; global setup file deleted.
Build output
tsconfig.build.json
New build tsconfig targeting dist with source maps; excludes tests/benchmarks from build.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client (TS)
    participant Wallet as Wallet/Deployer
    participant Chain as Blockchain/Node
    participant Macro as Immutables Macro (Noir)
    participant PXE as PXE Capsule Store

    Client->>Wallet: serialize immutables -> Fr[]
    Client->>Wallet: computeContractSalt(actualSalt, serialized)
    Client->>Wallet: createImmutablesCapsule(address?, actualSalt, serialized)
    Wallet->>Chain: deployWithImmutables(instance, publish?)
    Chain->>Macro: on-deploy (generated init/load paths)
    Macro->>PXE: store or load capsuleData
    PXE-->>Macro: capsuleData
    Client->>Chain: send tx to account/contract
    Chain->>Macro: Immutables::init(context) -> load & verify capsule via PXE
    Macro-->>Chain: deserialized immutables (public key)
    Chain-->>Client: tx result
Loading
sequenceDiagram
    participant Caller as Client (TS)
    participant Contract as ImmutablesContract (Noir)
    participant Capsule as Capsule Storage (PXE)
    participant Verifier as Immutables::init (Noir)

    Caller->>Contract: store_immutables(capsuleData)
    Contract->>Contract: computedSalt = poseidon2_hash(capsuleData)
    Contract->>Contract: assert computedSalt == contractSalt
    Contract->>Capsule: persist capsuleData
    Capsule-->>Contract: ok

    Caller->>Contract: get_signing_key()
    Contract->>Verifier: Immutables::init(context)
    Verifier->>Capsule: load capsuleData
    Capsule-->>Verifier: capsuleData
    Verifier->>Verifier: computedSalt = hash(capsuleData)
    Verifier->>Verifier: assert computedSalt == instanceSalt
    Verifier-->>Contract: deserialized immutables
    Contract-->>Caller: signing_key_x, signing_key_y
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • wei3erHase
  • 0xShaito
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: immutables macro' accurately reflects the primary change—introducing the #[immutables] macro pattern for Aztec Noir contracts to enable initializerless contract deployments.
Description check ✅ Passed The description provides comprehensive coverage of the macro implementation, contracts, TypeScript SDK, tests, benchmarks, and CI changes. It includes details on key mechanisms (salt derivation, capsule verification, storage patterns) and references to related PRs and tracking issues.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/immutables-macro

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

20 issues found across 55 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/ts/immutables/index.ts">

<violation number="1" location="src/ts/immutables/index.ts:191">
P1: Immutables length validation occurs after `wallet.registerContract()`. If the check fails, the contract is already registered in PXE, leaving an inconsistent state. Move this validation before the `registerContract` call.</violation>

<violation number="2" location="src/ts/immutables/index.ts:260">
P2: Custom agent: **TypeScript & React Standards**

Avoid `as any` cast — use a proper type assertion or fix the type mismatch with `poseidon2Hash`. If the function accepts `Fr[]`, cast to the correct type (e.g., `as Fr[]`) or adjust the input to match the expected signature.</violation>

<violation number="3" location="src/ts/immutables/index.ts:309">
P1: Custom agent: **TypeScript & React Standards**

Use `unknown[]` instead of `any[]` for `initializerArgs`. The rule requires avoiding `any` and using `unknown` when the type is not known. Since this is a public interface, `any` propagates unchecked types to all callers.</violation>
</file>

<file name="README.md">

<violation number="1" location="README.md:119">
P2: Incorrect example value for `N`. The text says `N = 3` for a struct with two `Field` values, but since the array is `[Field; 1 + N]` (where `1` is the `actual_salt`), `N` should be `2` (the serialized length of just the immutables). Using `N = 3` would produce `[Field; 4]`, which is wrong. The reference implementation below confirms this: `[Field; 3]` for a 2-field struct.</violation>
</file>

<file name="src/ts/schnorr-initializerless-account.test.ts">

<violation number="1" location="src/ts/schnorr-initializerless-account.test.ts:52">
P2: Custom agent: **Test File Standards**

All test descriptions in this file use "should", which violates the test naming guideline. Prefer imperative or declarative phrasing, e.g. `"produces different addresses for different signing keys"` or `"deploys account with signing key and reads it back"`.

This applies to all 9 `it(...)` blocks in the file.</violation>

<violation number="2" location="src/ts/schnorr-initializerless-account.test.ts:78">
P2: Custom agent: **Test File Standards**

This test conflates four distinct behaviors (non-zero check, idempotency, key sensitivity, salt sensitivity) into a single test case. Split into separate tests — e.g. `"computes non-zero salt"`, `"computes deterministic salt for same inputs"`, `"computes different salt for different keys"`, `"computes different salt for different actualSalt"`.</violation>

<violation number="3" location="src/ts/schnorr-initializerless-account.test.ts:167">
P2: These negative tests under the "Published" describe block deploy without `publishClass`/`publishInstance` flags, so they actually test the unpublished code path. Pass the same publish options as the other tests in this block to ensure the published path's capsule validation is exercised.</violation>
</file>

<file name="src/ts/utils.ts">

<violation number="1" location="src/ts/utils.ts:16">
P2: Custom agent: **TypeScript & React Standards**

Environment variable `NODE_URL` is read without runtime type-checking. The rule requires runtime validation for environment variables (e.g., using Zod). Consider defining a schema that validates the value is a proper URL string.</violation>

<violation number="2" location="src/ts/utils.ts:57">
P2: Custom agent: **TypeScript & React Standards**

Exported function `setupTestSuite` is missing an explicit return type. It returns a complex object with `node`, `wallet`, `accounts`, `sponsoredPaymentMethod`, and `cleanup` — define a named return type (e.g., `Promise<TestSuiteContext>`) so consumers get clear type documentation without relying on inference.</violation>

<violation number="3" location="src/ts/utils.ts:73">
P2: If `wallet.stop()` throws, the temp directory is never cleaned up. Wrap `wallet.stop()` in a try/finally (or its own try/catch) so `rmSync` always runs.</violation>
</file>

<file name="src/nr/schnorr_initializerless_account_contract/src/main.nr">

<violation number="1" location="src/nr/schnorr_initializerless_account_contract/src/main.nr:79">
P0: Missing `#[noinitcheck]` on `entrypoint`. This is an initializerless contract (no `#[initializer]`), so the deployment nullifier is never emitted. Without `#[noinitcheck]`, the `#[aztec]` macro's default init-check will reject every call to this function. Both the standard `SchnorrAccount` and the `ImmutablesContract` use `#[noinitcheck]` for the same reason.</violation>

<violation number="2" location="src/nr/schnorr_initializerless_account_contract/src/main.nr:94">
P0: Missing `#[noinitcheck]` on `verify_private_authwit`. Same issue as `entrypoint` — without it, the init-check will fail since no deployment nullifier exists for this initializerless contract.</violation>

<violation number="3" location="src/nr/schnorr_initializerless_account_contract/src/main.nr:188">
P1: Missing `#[noinitcheck]` on `get_signing_public_key`. Same init-check issue as the other private functions — this will fail at runtime without the attribute.</violation>
</file>

<file name="src/ts/schnorr-account/utils.ts">

<violation number="1" location="src/ts/schnorr-account/utils.ts:76">
P2: Custom agent: **TypeScript & React Standards**

Use `unknown` instead of `any` for `paymentMethod`. The rule states: "Avoid `any`; use `unknown` when necessary." If a more specific type from the Aztec SDK is available (e.g., `FeePaymentMethod`), prefer that; otherwise use `unknown`.</violation>

<violation number="2" location="src/ts/schnorr-account/utils.ts:85">
P2: Bug: `signingPublicKey` is computed from the private key scalar's `.lo`/`.hi` halves, not from an actual Grumpkin point derivation. `deriveSigningKey` returns a `Fq` scalar; splitting it into two halves does not produce curve point coordinates. You need to derive the public key by multiplying the scalar by the generator (e.g., `Schnorr.computePublicKey`).</violation>
</file>

<file name="src/ts/schnorr-initializerless-account/index.ts">

<violation number="1" location="src/ts/schnorr-initializerless-account/index.ts:282">
P0: Critical bug: `createSchnorrInitializerlessAccount` uses `GrumpkinScalar.fromHighLow(Fr.ZERO, secretKey)` for key derivation, but `deploySchnorrInitializerlessAccount` uses `deriveSigningKey(secretKey)`. These produce different signing keys from the same secret, making the two functions incompatible. The factory function should use the same derivation as the deploy function.</violation>
</file>

<file name="src/ts/e2e.test.ts">

<violation number="1" location="src/ts/e2e.test.ts:95">
P2: Custom agent: **Test File Standards**

All test descriptions use "should" — the rule explicitly prohibits this. Prefer declarative names like `"mints to private balance of initializerless account"`, `"allows unpublished account to send private transactions"`, etc. This applies to all 7 `it(...)` blocks in this file.</violation>

<violation number="2" location="src/ts/e2e.test.ts:227">
P1: Custom agent: **Test File Standards**

This test conflates multiple behaviors: three distinct transfers (private→private, private→public, and reverse private→private), intermediate balance checks after each, and final balance verification for four balances. Break this into separate tests — e.g., one for initializerless→standard transfer, one for private→public self-transfer, one for standard→initializerless transfer. Each test can set up its own accounts and verify a single transfer behavior.</violation>
</file>

<file name="src/ts/immutables-contract.test.ts">

<violation number="1" location="src/ts/immutables-contract.test.ts:44">
P2: Custom agent: **Test File Standards**

All 12 test descriptions use the word "should", which the test file standards rule explicitly prohibits. Use imperative/declarative phrasing instead — e.g., `"produces different addresses for different actualSalt"`, `"rejects store_immutables with wrong data"`, `"deploys contract with immutables and reads them back"`.</violation>

<violation number="2" location="src/ts/immutables-contract.test.ts:61">
P2: Custom agent: **Test File Standards**

This test conflates four independent behaviors (non-zero salt, determinism, immutables-sensitivity, actualSalt-sensitivity) into a single test case. Per the test standards rule, each test should test one behavior. Split into separate tests like `"computes non-zero salt"`, `"computes deterministic salt for same inputs"`, `"computes different salt for different immutables"`, and `"computes different salt for different actualSalt"`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/nr/schnorr_initializerless_account_contract/src/main.nr
Comment thread src/nr/schnorr_initializerless_account_contract/src/main.nr
Comment thread src/ts/schnorr-initializerless-account/index.ts Outdated
Comment thread src/ts/immutables/index.ts
Comment thread src/nr/schnorr_initializerless_account_contract/src/main.nr
Comment thread src/ts/schnorr-initializerless-account.test.ts
Comment thread src/ts/immutables/index.ts
Comment thread src/ts/schnorr-account/utils.ts
Comment thread src/ts/immutables-contract.test.ts
Comment thread src/ts/immutables-contract.test.ts
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 3, 2026

Benchmark Comparison

CPU Cores RAM Arch
AMD EPYC 7763 64-Core Processor 16 63 GiB x64

Contract: account

Function Gates DA Gas L2 Gas Proving Time (ms)
Status Base PR Diff Base PR Diff Base PR Diff Base PR Diff
🆕 Immutables Account: transfer_private_to_private 0 537,939 +Inf% 0 1,312 +Inf% 0 512 +Inf% N/A 7,051 +Inf%
🆕 Immutables Account: transfer_private_to_public 0 573,546 +Inf% 0 800 +Inf% 0 149,749 +Inf% N/A 7,380 +Inf%
🆕 Standard Account: deploy + initialize 0 511,144 +Inf% 0 768 +Inf% 0 512 +Inf% N/A 6,850 +Inf%
🆕 Standard Account: transfer_private_to_private 0 536,841 +Inf% 0 1,312 +Inf% 0 512 +Inf% N/A 7,002 +Inf%
🆕 Standard Account: transfer_private_to_public 0 572,448 +Inf% 0 800 +Inf% 0 149,749 +Inf% N/A 7,388 +Inf%

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 4, 2026

Benchmark Comparison

CPU Cores RAM Arch
AMD EPYC 7763 64-Core Processor 16 63 GiB x64

Contract: account

Function Gates DA Gas L2 Gas Proving Time (ms)
Status Base PR Diff Base PR Diff Base PR Diff Base PR Diff
🆕 Immutables Account: transfer_private_to_private 0 537,939 +Inf% 0 1,312 +Inf% 0 512 +Inf% N/A 6,908 +Inf%
🆕 Immutables Account: transfer_private_to_public 0 573,546 +Inf% 0 800 +Inf% 0 149,749 +Inf% N/A 7,252 +Inf%
🆕 Standard Account: deploy + initialize 0 511,144 +Inf% 0 768 +Inf% 0 512 +Inf% N/A 6,867 +Inf%
🆕 Standard Account: transfer_private_to_private 0 536,841 +Inf% 0 1,312 +Inf% 0 512 +Inf% N/A 6,976 +Inf%
🆕 Standard Account: transfer_private_to_public 0 572,448 +Inf% 0 800 +Inf% 0 149,749 +Inf% N/A 7,247 +Inf%

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 9 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="README.md">

<violation number="1" location="README.md:133">
P3: The README examples now require a `deployer` argument but never show how to define it (e.g., `const deployer = wallet.getAddress();`), so the snippets won’t run as written.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread README.md
Comment thread src/nr/counter_contract/src/main.nr Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why are we using aztec-standards token instead of using the counter for testing / benchmarking?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

the repo started from a previous one, but agree it's unnecessary as counter covers public and private fns. Then only added value of token is testing with notes, which is nice for wallet implementations.

use crate::ImmutablesContract;
use crate::test::utils::setup;

// TODO: The TXE (Test Execution Environment) does not support deploying contracts
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

do we have an open issue on their repo to highlight this need?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

They just closed it yesterday feat: add salt and secret params to env.deploy, we'll be able to test this in the version that includes it (also useful for escrow tests as the logic contract address is the salt of the escrow contract)

Comment on lines +289 to +290
// Increment counter via public function
await contract.methods.increment_counter().send({ from: alice });
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

how come we're not using the previous counter and adding some methods, instead of redeclaring it on the "MixedBehaviour" contract?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

the repo started from a previous one, was kind of a merging with boilerplate, but agree that would have been better

wei3erHase
wei3erHase previously approved these changes Mar 4, 2026
Copy link
Copy Markdown
Member

@wei3erHase wei3erHase left a comment

Choose a reason for hiding this comment

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

oki, great work, i've would have preferred not importing aztec-standards token to test, or make smaller PRs into dev, but seems a good starting point

turtlemoji
turtlemoji previously approved these changes Mar 6, 2026
@turtlemoji turtlemoji self-requested a review March 6, 2026 08:41
coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 6, 2026
@zkfrov zkfrov dismissed stale reviews from coderabbitai[bot], turtlemoji, and wei3erHase via bd05afa March 6, 2026 13:12
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 6, 2026

Benchmark Comparison

CPU Cores RAM Arch
AMD EPYC 7763 64-Core Processor 16 63 GiB x64

Contract: account

Function Gates DA Gas L2 Gas Proving Time (ms)
Status Base PR Diff Base PR Diff Base PR Diff Base PR Diff
🆕 Immutables Account: transfer_private_to_private 0 537,939 +Inf% 0 1,312 +Inf% 0 512 +Inf% N/A 7,175 +Inf%
🆕 Immutables Account: transfer_private_to_public 0 573,546 +Inf% 0 800 +Inf% 0 149,749 +Inf% N/A 7,389 +Inf%
🆕 Standard Account: deploy + initialize 0 511,144 +Inf% 0 768 +Inf% 0 512 +Inf% N/A 6,896 +Inf%
🆕 Standard Account: transfer_private_to_private 0 536,841 +Inf% 0 1,312 +Inf% 0 512 +Inf% N/A 7,100 +Inf%
🆕 Standard Account: transfer_private_to_public 0 572,448 +Inf% 0 800 +Inf% 0 149,749 +Inf% N/A 7,354 +Inf%

Copy link
Copy Markdown
Member

@wei3erHase wei3erHase left a comment

Choose a reason for hiding this comment

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

🚢

@zkfrov zkfrov merged commit a4e6b27 into dev Mar 6, 2026
8 of 9 checks passed
@zkfrov zkfrov deleted the feat/immutables-macro branch March 6, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants