Private allocations. Public rules. TokenOps execution.
Token distribution on a public chain leaks your company strategy. Anyone can read transfers and vesting contracts to reverse-engineer who your biggest backers are, which contributors you rank highest, what your advisors negotiated, and when each party moves. That's competitive and personal intelligence, exposed by default.
CloakOps is a confidential operations layer on top of TokenOps, built on Zama FHE. Token teams run private rounds, contributor rewards, advisor vesting, and community distributions where allocation amounts, tiers, and vesting metadata stay encrypted on-chain — while campaign rules and totals remain publicly verifiable. The headline capability: CloakOps funds many confidential stakeholders in a single, fixed-signature batch through Multicall3 — the multi-recipient flow the TokenOps dashboard can't yet do, on the same contract that can.
Built for the Zama Developer Program (Mainnet Season 3) — Builder Track and the TokenOps Special Bounty.
| Link | |
|---|---|
| Live demo | cloak-ops.vercel.app |
| Video demo | Add your Loom / YouTube URL |
| ConfidentialCampaign (Sepolia) | 0x8bE1…aF7e |
| TokenOps funding (example tx) | 0x3de4…2cd9e |
Full submission pack (pitch, demo order, checklist): docs/SUBMISSION.md.
Public chains leak distribution strategy. Anyone can read token transfers and vesting contracts to infer who got the biggest allocation, which contributors are top-tier, what advisors received, and when each party claimed.
Ordinary encryption doesn't solve it: you can't run claim logic or prove campaign totals over data nobody can compute on.
Fully Homomorphic Encryption (FHE) lets a smart contract operate on
encrypted values directly. CloakOps stores each recipient's allocation
(euint64), tier (euint8), and vesting class (euint8) encrypted, with
per-recipient FHE access control so only the recipient can decrypt their own
values. On claim, the still-encrypted allocation is credited to the
recipient's confidential token balance via an on-chain FHE.add — the
payout amount is never revealed publicly.
TokenOps provides the campaign and distribution lifecycle rail; CloakOps adds the confidential metadata layer.
flowchart LR
A["Admin browser<br/>Zama Relayer SDK"] -->|"encrypt euint64 / euint8"| B["ConfidentialCampaign.sol<br/>encrypted allocation + tier + vesting class<br/>(single source of truth)"]
B -->|"FHE.allow per recipient"| C["Recipient browser<br/>userDecrypt"]
C -->|"claim()"| D{"FHE tier bonus<br/>FHE.gt / FHE.select"}
D -->|"FHE.add (still encrypted)"| E["CloakConfidentialToken<br/>confidential balance (euint64)"]
B -->|"same encrypted amount"| F["TokenOps factory<br/>create + batchFund via Multicall3"]
F --> G["Per-recipient confidential<br/>vesting wallets"]
Everything left of the recipient stays encrypted end to end: the admin encrypts in-browser, the contract stores and computes on ciphertext, and only the recipient can decrypt their own row. The same encrypted allocation drives both the instant claim rail and the schedule-based TokenOps vesting rail.
CloakOps drives two complementary, confidential settlement paths from the same encrypted allocation — neither ever reveals the amount publicly:
| CloakOps confidential claim | TokenOps confidential vesting | |
|---|---|---|
| Contract | CloakConfidentialToken (FHE.add) |
TokenOps …CliffExecutorConfidentialFactory |
| Trigger | Recipient calls claim() |
Admin runs the create flow |
| Effect | Credits recipient's encrypted balance instantly | Deploys + funds a per-recipient vesting wallet that releases on a schedule |
| Amount privacy | euint64, recipient-decryptable only |
euint64 encrypted in-browser before funding |
The encrypted allocation in ConfidentialCampaign.sol is the single source of
truth; the claim rail proves the FHE payout primitive end-to-end, while the
TokenOps rail proves the same encrypted amount can drive real, schedule-based
vesting wallets. On-chain proof: docs/tokenops-integration.md.
| Track | What CloakOps demonstrates |
|---|---|
| Zama Builder Track | End-to-end FHE dApp: client encrypt → on-chain euint64/euint8 storage → recipient userDecrypt → claim payout via FHE.add on CloakConfidentialToken. Deployed on Sepolia with the Zama Relayer SDK. |
| TokenOps Special Bounty | Real on-chain integration with the TokenOps confidential vesting factory: createVestingWalletConfidential (deploy) + batchFundVestingWalletConfidential (fund) with browser-encrypted euint64 amounts, batched through Multicall3 so signatures stay fixed regardless of stakeholder count, plus a live operation log in the UI. See docs/tokenops-integration.md. |
CloakOps is a product extension on top of TokenOps confidential vesting, not a parallel reimplementation:
- A metadata layer the TokenOps UI doesn't expose — confidential, per-recipient
tier (
euint8) and vesting class (euint8) alongside the encrypted allocation, with FHE access control so only each recipient can decrypt their own row. TokenOps moves the tokens; CloakOps encodes who they are and on what terms, confidentially. - Past the UI's single-stakeholder cap — the dashboard wizard funds one stakeholder at a time, so CloakOps calls the same factory directly and batches many stakeholders (deploy + fund) through Multicall3 in a fixed signature count — the multi-recipient flow the UI can't yet do, on the contract that can.
- A confidential campaign front-end + public audit page — admins run encrypted campaigns and anyone can verify public rules (budget, window, claimed count) while every allocation stays encrypted, end to end.
| Public & verifiable | Encrypted (Zama FHE) | Honestly not hidden (MVP) |
|---|---|---|
| Campaign name & type | Allocation amount (euint64) |
Recipient wallet addresses |
| Total budget | Recipient tier (euint8) |
Transaction timing |
| Recipient count | Vesting class (euint8) |
Admin address |
| Claim window | Confidential token balance (euint64) |
|
| Claimed count | (decryptable only by recipient) | |
| Contract address |
Full detail: docs/privacy-model.md.
Architecture deep dive: docs/architecture.md.
- Node.js >= 20, npm >= 9
- MetaMask (or compatible wallet) on Sepolia with test ETH
npm install
npm run dev
# → http://localhost:3000Configure the frontend env first — copy .env.example to
apps/web/.env.local and fill in the deployed contract addresses (see
Sepolia deployments below).
/admin— connect admin wallet on Sepolia → add recipients via the form (or paste/upload CSV) → Create confidential campaign. Watch the 5-step flow: parse → Zama encrypt → contract submit → TokenOps sync → ready. Each on-chain step prompts a wallet signature./claim— connect a recipient wallet → the page auto-scans the contract for eligible campaigns → decrypt allocation/tier/vesting → Claim allocation → decrypt your confidential token balance (credited via on-chainFHE.add)./public-audit— anyone can browse all campaigns read directly from Sepolia (works in incognito — no localStorage required) and verify public rules while private fields stay encrypted.
Wrong network / failed txs? Each page surfaces a human-readable notice: a wrong-network banner prompts a one-click switch to Sepolia, and reverted or rejected transactions decode into a plain-language
ErrorNoticeinstead of a raw RPC dump.
npm run compile # Solidity 0.8.27, cancun, viaIR
npm run test # 20 FHEVM mock-mode testsRoot .env (Hardhat only — see Environment):
npm run deploy:sepolia # ConfidentialCampaign + CloakConfidentialToken
npm run export-abi # sync ABI + addresses → apps/web/lib/contractsThen update apps/web/.env.local:
NEXT_PUBLIC_CLOAKOPS_CONTRACT_ADDRESS=0x...
NEXT_PUBLIC_CLOAKOPS_TOKEN_ADDRESS=0x...
NEXT_PUBLIC_TOKENOPS_VESTING_FACTORY=0x98c519f9de1dc8c8cb3eb9b0b09b3ce057beb72a
NEXT_PUBLIC_TOKENOPS_VESTING_TOKEN=0xFaac272CDE1701479932935a3567652873c377EF
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=...
ZAMA_RELAYER_URL=https://relayer.testnet.zama.org/v2| Component | Address / link |
|---|---|
ConfidentialCampaign |
0x8bE1695FEa146cBb84d292d68f7682D118a0aF7e |
CloakConfidentialToken (cCLOAK) |
0x83e62cB81240dc73d7d3e2d812E5559EA0435376 |
| TokenOps vesting factory | 0x98c519f9de1dc8c8cb3eb9b0b09b3ce057beb72a |
| TokenOps vesting token (CTestToken) | 0xFaac272CDE1701479932935a3567652873c377EF |
ConfidentialCampaign.sol — campaign metadata + encrypted per-recipient
allocations + claim logic. On claim(), grants transient FHE access to the
campaign token and credits the recipient's encrypted balance.
CloakConfidentialToken.sol — ERC-7984-style confidential balance token;
creditConfidential performs FHE.add so running balances stay encrypted.
Full contract + frontend architecture: docs/architecture.md.
- Root directory:
apps/web - Env vars: all
NEXT_PUBLIC_*from.env.local, plus server-sideZAMA_RELAYER_URL(relayer proxy at/api/relayer/[chainId]) - Do not put
PRIVATE_KEYin Vercel
| File | Purpose |
|---|---|
Root .env |
Hardhat deploy only: SEPOLIA_RPC_URL, PRIVATE_KEY, ETHERSCAN_API_KEY |
apps/web/.env.local |
Next.js frontend: contract addresses, TokenOps, WalletConnect, relayer |
Template: .env.example. No secrets are committed (both files are gitignored).
- The claim rail is a live proof of the FHE payout primitive, not a mock.
On Sepolia, a tier-3 recipient with a
25000encrypted allocation claims and receives a27500confidential balance — the+10%loyalty bonus is computed on-chain withFHE.gt/FHE.select/FHE.addover ciphertext, and only the recipient can decrypt the result. It creditsCloakConfidentialToken(a testnet demo asset) rather than moving pre-funded production tokens, but the encrypted arithmetic and access control are the real, end-to-end mechanism. - Recipient addresses, tx timing, and the admin address are visible on-chain (see the privacy model above — this is an honest MVP boundary, not a leak).
- Roadmap: production ERC-7984 settlement via TokenOps rails, encrypted vesting enforcement on-chain, multi-admin campaigns.
ERC-20↔ERC-7984 wrapper registry, wrap/unwrap UI, payroll, governance, cross-chain, billing, KYC, mainnet deployment.
MIT
