Skip to content

refactor(token): CFT supply extension and integration composition - #10

Merged
andrew-fleming merged 4 commits into
andrew-fleming:add-cft-2from
OpenZeppelin:refactor/cft-supply-extension
Jul 21, 2026
Merged

refactor(token): CFT supply extension and integration composition#10
andrew-fleming merged 4 commits into
andrew-fleming:add-cft-2from
OpenZeppelin:refactor/cft-supply-extension

Conversation

@0xisk

@0xisk 0xisk commented Jul 20, 2026

Copy link
Copy Markdown

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. Layout proposal for OpenZeppelin#653 (Confidential Fungible Token, tracking OpenZeppelin#569), targeting add-cft-2 so it can merge into that PR directly.

What this proposes

Restructure the CFT layout so the shipped library is one token module plus one optional supply extension, with the assembled token living in the integration suite's mocks:

src/token/ConfidentialFungibleToken.compact                   (renamed from ConfidentialFungibleTokenCore;
                                                               gains _mint/_burn/_burnFrom building blocks)
src/token/extensions/ConfidentialFungibleTokenSupply.compact  (supply tracker: _totalSupply,
                                                               _addSupply/_subSupply, totalSupply())
test/integration/_mocks/ConfidentialFungibleTokenPublicSupply.compact
                                                              (TEST-ONLY top-level contract composing both)

Commit by commit:

  1. refactor(token): drop Core suffix from the CFT module — the NST family keeps a Core because two wrappers share it; CFT has one flavor, so the module consumers import is just ConfidentialFungibleToken.
  2. feat(token): add _mint/_burn/_burnFrom building blocks — thin intent-named aliases over _credit/_debit/_spendEscrow (which transfer/_move keep using internally). No supply accounting; a composing contract gates them and pairs them with the tracker.
  3. feat(token): add ConfidentialFungibleTokenSupply extension — mirrors NativeShieldedTokenSupply: imports no token module, exposes the scalar accounting blocks plus the getter; the original error strings are preserved.
  4. refactor(token): move the composed CFT token to integration mocks — the assembled token (former ConfidentialFungibleTokenPublicSupply module) integrates two production pieces, so it moves out of src/ and becomes a top-level TEST-ONLY contract, pairing every supply op with its accounting block (mint = _addSupply + _mint, burn = _burn + _subSupply, burnFrom = _burnFrom + _subSupply). Its unit mock, simulator, and test file are removed with it.

Testing notes

  • Every touched contract compiles (compact compile --skip-zk, artifacts verified); tsc --noEmit and biome ci are clean.
  • Deliberate coverage gap: the old ConfidentialFungibleTokenPublicSupply unit suite is removed here, and the replacement — a per-case integration spec suite under test/integration/specs/confidentialFungibleToken/ (mint/burn/burnFrom, supply conservation, privacy, concurrency) driving the composed contract — is ready and follows in a separate PR to keep this one reviewable. The base ConfidentialFungibleToken unit suite is untouched.

PR Checklist

  • I have read the Contributing Guide
  • I have added tests that prove my fix is effective or that my feature works. See GUIDELINES.md#testing for more information. (spec suite in a follow-up PR, see testing notes)
  • I have added documentation for new methods or changes to existing method behavior. See GUIDELINES.md#documentation for more information.
  • CI Workflows Are Passing

Further comments

  • Why supply-as-extension: the base stays supply-neutral (conserving surface + intent-named blocks), matching the NST precedent (extensions/NativeShieldedTokenSupply) and leaving room for a confidential-supply sibling (ElGamal cell + auditor viewing key) without touching the base.
  • Why the assembled token is test-only: an ungated mint is a faucet, so shipping it as an importable "batteries-included" module invites unsafe deployments. As an integration mock the DANGER surface disappears. Whether the library should also ship a gated deployable preset (e.g. mint behind Ownable) is worth discussing.

0xisk added 4 commits July 20, 2026 15:02
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.

@andrew-fleming andrew-fleming left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks @0xisk! Much cleaner and simpler than what I was thinking

@andrew-fleming
andrew-fleming merged commit 60cecbd into andrew-fleming:add-cft-2 Jul 21, 2026
2 checks passed
@andrew-fleming
andrew-fleming deleted the refactor/cft-supply-extension branch July 21, 2026 01:46
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