Confidential savings vaults and contribution circles on Zama FHEVM.
Circux is a confidential savings and contribution platform built for individuals and groups using Zama FHE. Personal vault balances, group treasury values, and member contribution totals stay encrypted on-chain, while users still get clear rules, visible progress, invite-based membership, and auditable event history.
- Why Circux
- Current Scope
- Core Flows
- Architecture
- Contracts
- Frontend
- Backend
- Subgraph
- Local Setup
- Testing
- Documentation
- Repository Layout
- License
Savings products usually force a privacy tradeoff. Centralized apps hide balances from the public, but users must trust the operator. Public on-chain apps are verifiable, but balances and contribution behavior can become exposed.
Circux uses FHE-powered confidential tokens so the system can coordinate savings while keeping sensitive amounts private.
- Private personal vaults: users save toward a target without publicly exposing balances.
- Private group contribution circles: members can contribute to a shared treasury while individual totals remain encrypted.
- Transparent rules: cadence, payout mode, target, membership, and payout readiness are visible product state.
- Selective reveal where appropriate: owners can reveal their own vault values; circle members can reveal permitted circle values and their own contribution totals.
- Event-driven history: factory, vault, circle, invite, and token events are indexed for durable UI history.
- Create a vault with a token, label, category, lock rule, target, and milestone count.
- Deposit encrypted
cUSDCorcUSDT. - Track encrypted balance and target-reached state.
- Request and execute withdrawals through the vault state machine.
- Support time-lock and milestone-based withdrawal rules.
- Create a circle with a token, cadence, payout mode, target, optional required contribution amount, and milestone count.
- Join a circle directly or through invite-assisted onboarding.
- Contribute encrypted
cUSDCorcUSDT. - Track member streaks, status, consistency bands, current round payment state, and circle health.
- Support rotating, milestone, and pooled payout modes.
- Allow organizers to release payouts only when the active payout rule is satisfied.
- Store onboarding/profile data in the backend.
- Generate circle-specific invite codes.
- Resolve invite codes during onboarding.
- List joined invite history and user affiliations in the profile area.
- Keep real circle membership on-chain through
joinCircle.
- Local deployments use mock
USDCandUSDT. - Confidential wrappers expose
cUSDCandcUSDTusing ERC-7984-style flows. - The frontend guides wrap/authorize/contribute or wrap/authorize/deposit steps with user-facing error messages.
Future / Hidden Scope
The matching pool and disclosure contracts are still present in the codebase, but matching and the standalone privacy center are not part of the main product navigation right now. They are retained as future expansion surfaces, not core user flows.
sequenceDiagram
participant User
participant UI
participant Token as cUSDC/cUSDT
participant Vault as CircuxVault
User->>UI: Enter deposit amount
UI->>Token: Ensure confidential balance / authorization
UI->>Vault: deposit(encryptedAmount, proof, streak)
Vault->>Token: confidentialTransferFrom(user, vault, amount)
Vault->>Vault: Refresh encrypted balance and target reached state
Vault-->>UI: VaultDeposited event
sequenceDiagram
participant Member
participant UI
participant Token as cUSDC/cUSDT
participant Circle as CircuxCircle
Member->>UI: Enter contribution amount
UI->>Token: Ensure confidential balance / authorization
UI->>Circle: contribute(encryptedAmount, proof)
Circle->>Token: confidentialTransferFrom(member, circle, amount)
Circle->>Circle: Update treasury, member state, health, round readiness
alt Rotating circle with required amount
UI->>Circle: verifyRoundContribution(member, cleartexts, proof)
Circle->>Circle: Mark member paid for current round
end
| Mode | Concept | Readiness rule |
|---|---|---|
ROTATING |
Members pay each round, then the next recipient receives the payout. Rounds can continue indefinitely. | Every active member has paid the current round. |
MILESTONE |
The circle pays out when encrypted treasury has reached the encrypted target. | Target-reached proof verifies against the encrypted state. |
POOLED |
Organizer requests a payout to a selected member from the shared pool. | Organizer requests a pooled payout, then executes the release. |
Wallets
|
v
Frontend (Next.js + wagmi/viem + FHE hooks)
|
+--> CircuxFactory
| +--> CircuxVault instances
| +--> CircuxCircle instances
| +--> CircuxMatchingPool instances (future-facing)
|
+--> ConfidentialUSDC / ConfidentialUSDT
| + wrap / confidential balances / confidential transfers
|
+--> Backend API (NestJS)
| + profiles
| + invites
| + activity records
|
+--> Subgraph
+ factory, vault, circle, token, invite-adjacent activity indexing
+ GraphQL data for dashboards and history
For a deeper system description, see docs/ARCHITECTURE.md.
Core contracts live in hardhat/contracts:
factory/CircuxFactory.sol- deploys and registers vaults, circles, and future matching pools.factory/CircuxCircleDeployer.sol- deploys circles separately to keep factory deployment manageable.CircuxVault.sol- encrypted personal vault, target tracking, lock rules, withdrawal state.CircuxCircle.sol- encrypted group treasury, membership, contribution policy, payout logic.DisclosureManager.sol- scoped disclosure grant primitive retained for future-facing flows.CircuxMatchingPool.sol- sponsor/matching primitive retained outside the main product flow.tokens/ConfidentialUSDC.solandtokens/ConfidentialUSDT.sol- confidential token wrappers.tokens/MockERC20.sol- local mock stablecoins.
The frontend lives in frontend and is built with Next.js 15, React 19, Tailwind CSS v4, wagmi, viem, and FHEVM client hooks.
Main user-facing routes:
/- landing page/onboarding- profile setup and optional invite code resolution/dashboard- overview of vaults, circles, balances, and recent activity/vaultsand/vaults/[id]- personal vault workflows/circlesand/circles/[id]- group contribution workflows/transactions- indexed activity/profile- profile, affiliations, and invite history
Hidden/future routes still exist for development:
/sponsor/disclosure
The backend lives in backend and uses NestJS + TypeORM.
It owns product data that should not be forced onto the contracts:
- onboarding profiles
- avatar/profile metadata
- invite code creation and redemption history
- user affiliations
- activity records used by the app shell
The subgraph lives in subgraph and indexes contract events into queryable entities for the UI.
Important mapping files:
src/factory.tssrc/vault.tssrc/circle.tssrc/token.tssrc/activity.tssrc/disclosure.tssrc/pool.ts
Current Sepolia deployment:
| Contract Name | Address | Explorer Link |
|---|---|---|
| CircuxFactory | 0xD226eD1549aFE9C99be915c2559512beD656Bf7C |
View on Etherscan |
| DisclosureManager | 0x1Cef0383435c633B684d7EA2d128e3B6f3Fd7f23 |
View on Etherscan |
| CircuxVault Implementation | 0x0344F6530765230799CfC9737c36a30Ba85bd136 |
View on Etherscan |
| CircuxCircle Implementation | 0xadAab3620baec639adab2bbBE8B6119282bD026f |
View on Etherscan |
| CircuxMatchingPool Implementation | 0xCfA3b82a5022C1398866CC0BA2Aed3B566576213 |
View on Etherscan |
| ConfidentialUSDC | 0x3202DBE009b1B7B8B0a9936Ccc4452e8EEaD0A5b |
View on Etherscan |
| ConfidentialUSDT | 0xeC4E39b84D3e5b9FDeC9496A438F4c90eb76C06F |
View on Etherscan |
| Sepolia USDC | 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238 |
View on Etherscan |
| Sepolia USDT | 0x93C5d30a7509E60871B77A3548a5BD913334cd35 |
View on Etherscan |
Deployment metadata lives in hardhat/deployments.json.
For a one-command local stack from the repository root:
docker compose up --buildThis starts Postgres, a local Hardhat node, deploys and exports contracts, starts the NestJS backend, then starts the Next.js frontend.
Default URLs:
- Frontend:
http://localhost:3000 - Backend:
http://localhost:4000/api/health - Local chain:
http://localhost:8545 - Backend Postgres:
localhost:5432
To include the local Graph Node/IPFS stack:
docker compose --profile subgraph up --buildSubgraph services expose:
- GraphQL:
http://localhost:8000/subgraphs/name/circux - Graph admin:
http://localhost:8020 - IPFS:
http://localhost:5001
Use the manual setup below if you want each service in a separate terminal.
- Node.js 20+
- npm
- Docker, if running the local graph node
- MetaMask or another local-wallet capable browser wallet
cd hardhat
npm install
npm run chainIn another terminal:
cd hardhat
npm run deploy:localhost
npm run fund:localhostTo also wrap mock USDC/USDT into confidential balances for local wallets:
cd hardhat
WRAP=true npm run fund:localhostcd backend
npm install
cp .env.example .env
npm run start:devcd subgraph
npm install
docker compose up -d
npm run codegen
npm run build
npm run create-local
npm run deploy-localcd frontend
npm install
npm run devThe app runs at http://localhost:3000 by default.
More setup details are in docs/LOCAL_DEVELOPMENT.md.
Circux has contract tests for the core FHE savings flows, plus type/build checks for the frontend, backend, and subgraph.
| Suite | Tests | Coverage |
|---|---|---|
CircuxVault.test.ts |
12 | Deposits, target setup, owner-only access, withdrawal request/execution, time locks, milestone proof validation. |
CircuxCircle.test.ts |
11 | Membership, decrypt access, encrypted contributions, cadence health, rotating rounds, pooled payouts, target updates. |
CircuxFactory.test.ts |
3 | Factory wiring, registry creation, and factory-created circle target setup. |
ConfidentialTokenRails.test.ts |
3 | Mock USDC/USDT wrapping, confidential wrapper authorization, and unwrap flow. |
DisclosureManager.test.ts |
2 | Disclosure grant creation, revocation, and double-revocation guard. |
CircuxMatchingPool.test.ts |
1 | Future-facing matching pool opt-in, funding, eligibility, and distribution state. |
Key contract test cases:
- Vaults cannot accept deposits before a target is configured.
- Vault withdrawals require the correct lock or milestone state and a prior withdrawal request.
- Circle members can join, contribute privately, and refresh decrypt access when needed.
- Rotating circles only count a member for a round after the paid-enough proof verifies.
- Ready rotating payouts reopen when a new member joins before payout execution.
- Milestone and pooled payouts are gated by their own readiness rules.
- Confidential token wrappers cover wrap, authorization, and unwrap behavior.
InputVerifierproof validation for encrypted inputs.- Encrypted handle storage and retrieval.
FHE.allow()permissions for owners, organizers, members, and token contracts.- Publicly decryptable boolean handles for target-reached and paid-enough checks.
- Proper ciphertext handling across vault deposits, circle contributions, and payout flows.
Contracts:
cd hardhat
npm run compile
npm testFrontend:
cd frontend
npm run typecheckBackend:
cd backend
npm run typecheckSubgraph:
cd subgraph
npm run codegen
npm run buildSee docs/TESTING.md for the expanded testing guide.
docs/ARCHITECTURE.md- system design and runtime flowsdocs/FEATURE_SCOPE.md- current features and future-facing surfacesdocs/LOCAL_DEVELOPMENT.md- local runbookdocs/TESTING.md- verification checklistdocs/TROUBLESHOOTING.md- common local/FHEVM issues
Circux/
├── backend/ # NestJS API for profiles, invites, affiliations, activity
├── frontend/ # Next.js app
├── hardhat/ # FHEVM contracts, deployments, tests, local scripts
├── subgraph/ # The Graph mappings/schema
├── docs/ # Architecture and project documentation
├── LICENSE
└── README.md
BSD-3-Clause-Clear. See LICENSE.