refactor(token): CFT supply extension and integration composition - #10
Merged
andrew-fleming merged 4 commits intoJul 21, 2026
Conversation
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.
This was referenced Jul 20, 2026
0xisk
marked this pull request as ready for review
July 20, 2026 14:22
andrew-fleming
approved these changes
Jul 21, 2026
andrew-fleming
left a comment
Owner
There was a problem hiding this comment.
Thanks @0xisk! Much cleaner and simpler than what I was thinking
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Types of changes
What types of changes does your code introduce to OpenZeppelin Midnight Contracts?
Put an
xin the boxes that applyFixes: N/A. Layout proposal for OpenZeppelin#653 (Confidential Fungible Token, tracking OpenZeppelin#569), targeting
add-cft-2so 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:
Commit by commit:
refactor(token): drop Core suffix from the CFT module— the NST family keeps aCorebecause two wrappers share it; CFT has one flavor, so the module consumers import is justConfidentialFungibleToken.feat(token): add _mint/_burn/_burnFrom building blocks— thin intent-named aliases over_credit/_debit/_spendEscrow(whichtransfer/_movekeep using internally). No supply accounting; a composing contract gates them and pairs them with the tracker.feat(token): add ConfidentialFungibleTokenSupply extension— mirrorsNativeShieldedTokenSupply: imports no token module, exposes the scalar accounting blocks plus the getter; the original error strings are preserved.refactor(token): move the composed CFT token to integration mocks— the assembled token (formerConfidentialFungibleTokenPublicSupplymodule) integrates two production pieces, so it moves out ofsrc/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
compact compile --skip-zk, artifacts verified);tsc --noEmitandbiome ciare clean.ConfidentialFungibleTokenPublicSupplyunit suite is removed here, and the replacement — a per-case integration spec suite undertest/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 baseConfidentialFungibleTokenunit suite is untouched.PR Checklist
Further comments
extensions/NativeShieldedTokenSupply) and leaving room for a confidential-supply sibling (ElGamal cell + auditor viewing key) without touching the base.mintis 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.mintbehindOwnable) is worth discussing.