Skip to content

test(integration): CFT composition spec suite#696

Draft
0xisk wants to merge 66 commits into
mainfrom
test/cft-integration-specs
Draft

test(integration): CFT composition spec suite#696
0xisk wants to merge 66 commits into
mainfrom
test/cft-integration-specs

Conversation

@0xisk

@0xisk 0xisk commented Jul 20, 2026

Copy link
Copy Markdown
Member

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: N/A. Test suite for the CFT layout proposal (#653 + andrew-fleming#10, tracking #569).

Stacked. This branch is #653 (add-cft-2 @ 5b645cc7) + the four refactor commits of andrew-fleming#10. Only the last three commits are new here; review 43a64b60..815a1615.

What this adds

The integration spec suite for the composed ConfidentialFungibleTokenPublicSupply contract (test/integration/_mocks/), closing the coverage gap that andrew-fleming#10 deliberately left open:

test/integration/fixtures/confidentialFungibleTokenPublicSupply.ts   (simulator + shared helpers)
test/integration/specs/confidentialFungibleToken/
  metadata.spec.ts            constructor/registration wiring smoke tests
  mint.spec.ts                paired _addSupply + _mint; pending credit, memo push, overflow guard
  burn.spec.ts                paired _burn + _subSupply; balance guards, hostile witness, no memo on debit
  burnFrom.spec.ts            escrow lifecycle: partial burns, exhaustion, no-escrow failure
  supplyConservation.spec.ts  sum(balances) == totalSupply: conserving ops never move the total
  privacy.spec.ts             observer-side properties from the public ledger only
  concurrency.spec.ts         the documented same-block limitation, proven deterministically

Commit by commit (the new three):

  1. test(integration): add the CFT composition fixture — simulator driving the composed artifact directly, plus shared helpers (test users, deployCft, actAs/registerAs, fundAs).
  2. test(integration): add the CFT composition spec suite — per-case specs following the specs/<topic>/<case>.spec.ts layout; ports the removed unit suite's coverage and adds the conservation invariant (only paired mint/burn/burnFrom may move totalSupply; transfer, approve/transferFrom, _move, sweep never do), a multi-user end-to-end flow, escrow burn-down/exhaustion, and memo-less-debit checks.
  3. test(integration): add CFT privacy and concurrency specs
    • privacy.spec asserts from the public ledger only: balances/pending/escrows stay ciphertexts, the approve cap never appears in clear, equal amounts are unlinkable, transfer reveals the counterparty graph but no amount, mint/burn disclose amounts through the supply delta by design, and hostile wallets (wrong EK, overstated plaintext or allowance) fail the witness-binding checks.
    • concurrency.spec documents the same-block limitation from the module header by proving its cause deterministically: with the witness seed pinned, an identical credit replayed on a changed recipient pre-state yields a different transcript (two transactions proven against one pre-state conflict), credits to distinct recipients touch disjoint cells, and sweep contests the same pending cell an incoming credit writes.

Testing notes

  • Runs under yarn test:integration (the integration vitest project; compile:integration builds the composed artifact).
  • tsc --noEmit and biome ci are clean.
  • Note: as integration specs these do not run in the live-test matrix (the unit-live project only globs src/**/*.test.ts).

PR Checklist

Further comments

Draft until #653 and andrew-fleming#10 settle; will rebase onto whatever shape they land in.

andrew-fleming and others added 30 commits June 21, 2026 16:40
PR #620 moved every unit suite to the async, backend-aware
@openzeppelin/compact-simulator@0.2.0 API, but the ElGamal suite added
on this branch still used the synchronous createSimulator path. Against
0.2.0 the spec fails to load (TypeError: Cannot read properties of
undefined reading 'kind'), which is the only failing suite in the test
workflow on #617.

* ElGamalSimulator: drop the sync constructor for `static async create`,
  add `artifactName: 'MockElGamal'`, and return `Promise<R>` from every
  pure pass-through (the assert circuits return `Promise<[]>`).
* ElGamal.test.ts: build the simulator in `beforeAll`, derive the shared
  keys once, await every circuit call, and assert failure paths with
  `await expect(...).rejects.toThrow(...)`.

No behavioral change to the contract; the migration is mechanical and
mirrors the UtilsSimulator / utils.test.ts pattern from #620.
test(crypto): migrate ElGamal suite to async simulator
andrew-fleming and others added 29 commits July 14, 2026 15:46
Rename ConfidentialFungibleTokenCore to ConfidentialFungibleToken: it
is the token module consumers import, not an internal shared core (the
NST family keeps a Core because two wrappers share it; CFT has one).
Mock, simulator, and test files follow the same rename.
Expose the supply-changing halves under their intent names: _mint
delegates to _credit, _burn to _debit, _burnFrom to _spendEscrow. They
perform no supply accounting; a composing contract pairs them with the
supply tracker extension when it wants a tracked totalSupply, and gates
them per its issuance policy. Docs updated to frame the module as
supply-neutral rather than supply-free.
Standalone public supply tracker mirroring NativeShieldedTokenSupply:
an _totalSupply cell with _addSupply/_subSupply building blocks and the
totalSupply getter, importing no token module. A consuming contract
calls the accounting block alongside the matching token op (_mint,
_burn, _burnFrom); the assembled pairing ships as the
ConfidentialFungibleTokenPublicSupply preset.
The assembled token (former ConfidentialFungibleTokenPublicSupply
module) composes two production pieces, so it leaves src/ and becomes a
top-level TEST-ONLY contract under test/integration/_mocks, pairing
every supply op with its accounting block: mint = _addSupply + _mint,
burn = _burn + _subSupply, burnFrom = _burnFrom + _subSupply.

The module's unit mock, simulator, and test suite are removed with it;
the composition's integration spec suite follows in a separate PR.
Simulator for the composed ConfidentialFungibleTokenPublicSupply
integration contract (driving its artifact directly), plus the shared
spec helpers: test users (ALICE/BOB), deployCft, actAs/registerAs, and
fundAs (mint + sweep + plaintext-cache for a fresh account).
Per-case specs under specs/confidentialFungibleToken/ (metadata, mint,
burn, burnFrom, supplyConservation), following the
specs/<topic>/<case>.spec.ts layout. Ports the coverage of the removed
unit suite and adds:

* supply conservation across transfer, approve/transferFrom, _move,
  and sweep (only paired mint/burn/burnFrom may move totalSupply)
* multi-user end-to-end mint -> transfer -> sweep -> burn flow
* escrow burn-down to zero and the exhaustion failure
* burnFrom with no escrow
* burn pushes no memo (debits are memo-less)
* registration and metadata wiring smoke tests
privacy.spec observes only the public ledger: balances, pending, and
escrows stay ciphertexts; the approve cap never appears in clear;
transfer leaks the counterparty graph (memo growth) but no amount;
mint/burn disclose their amounts through the totalSupply delta by
design; hostile wallets (wrong EK, overstated plaintext or allowance)
fail the witness-binding checks.

concurrency.spec documents the same-block limitation from the module
header by proving its cause deterministically: with the witness seed
pinned, an identical credit replayed on top of a changed recipient
pre-state yields a different transcript (so two same-pre-state
transactions conflict), credits to distinct recipients touch disjoint
cells (no conflict), and sweep contests the same pending cell an
incoming credit writes.
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

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.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c8a60f0f-1f5e-4e30-8a13-6ee5049500b7

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/cft-integration-specs

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants