refactor(token): CFT supply extension and integration composition - #9
Closed
0xisk wants to merge 6 commits into
Closed
refactor(token): CFT supply extension and integration composition#90xisk wants to merge 6 commits into
0xisk wants to merge 6 commits into
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 (module surface + supply accounting) is a composition of two production pieces, so it moves out of src/ and into the integration suite as a top-level TEST-ONLY contract (test/integration/_mocks/ConfidentialFungibleTokenPublicSupply). It pairs every supply-changing op with its accounting block: mint = _addSupply + _mint, burn = _burn + _subSupply, burnFrom = _burnFrom + _subSupply. The unit mock is superseded by driving the composed artifact directly; the simulator moves to the integration fixtures with shared spec helpers (users, deploy, funding) added.
Split the former single supply test file into per-case specs under specs/confidentialFungibleToken/ (metadata, mint, burn, burnFrom, supplyConservation), following the specs/<topic>/<case>.spec.ts layout. New coverage beyond the original suite: * 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.
Author
|
Superseded by #10, which keeps the refactor plus the composed integration contract and defers the spec suite to a follow-up PR. |
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 test suite:
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(test): compose CFT public supply in the integration suite— the assembled token (formerConfidentialFungibleTokenPublicSupplymodule) integrates two production pieces, so it moves out ofsrc/and becomes a top-level TEST-ONLY contract driven directly through its artifact; the unit mock is deleted and the simulator becomes an integration fixture with shared helpers.test(integration): add the CFT composition spec suite— the former single test file split into per-case specs (metadata,mint,burn,burnFrom,supplyConservation), following thespecs/<topic>/<case>.spec.tslayout, with new coverage for the conservation invariant (sum(balances) == totalSupply: only paired mint/burn/burnFrom may move the total; transfer, approve/transferFrom,_move, and sweep never do).test(integration): add CFT privacy and concurrency specs—privacy.specasserts observer-side properties 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.specdocuments 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
compact compile --skip-zk, artifacts verified),tsc --noEmitandbiome ciare clean.yarn test:integration.src/**removes it from the live-test matrix (theunit-liveproject only globssrc/**/*.test.ts).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, and the composition still gets a full spec. Whether the library should also ship a gated deployable preset (e.g.mintbehindOwnable) is worth discussing.