Deployment
Your DAO is deploy-your-own — you inherit PrivateDaoAdapter and deploy your contract. The
membership verifier is shared, reusable infrastructure: point your DAO at the pre-deployed one
instead of redeploying a multi-million-gas contract.
Reusable deployments
The verifier matching the bundled circuit is live on Sepolia
(deployments.json in the
package lists these):
| Contract | Sepolia address |
|---|---|
| HonkVerifier (membership verifier) | 0x6554ebdBc25e9023BC80006775958be57f8d8ea1 |
| ZKTranscriptLib (linked library) | 0xa567D41325Cfc5670827eCfDc980f7e381791d27 |
import deployments from "@privacy-protocol/cipher-contracts/deployments.json";
const { HonkVerifier } = deployments["ethereum-sepolia"];Deploy your DAO
Bring your own confidential votes token and (optionally) a membership root.
// scripts/deploy.ts
import { ethers } from "hardhat";
const VERIFIER = "0x6554ebdBc25e9023BC80006775958be57f8d8ea1"; // reuse the shared verifier
const TOKEN = process.env.VOTES_TOKEN!; // your ERC-7984 votes token
const MEMBERSHIP_ROOT = process.env.MEMBERSHIP_ROOT!; // Poseidon2 root of your members
async function main() {
const MyDao = await ethers.getContractFactory("MyDao");
const dao = await MyDao.deploy(TOKEN, VERIFIER, MEMBERSHIP_ROOT);
await dao.waitForDeployment();
console.log("MyDao:", await dao.getAddress());
}
main().catch((e) => { console.error(e); process.exitCode = 1; });npx hardhat run scripts/deploy.ts --network sepoliaStart confidential-only (no ZK)
Deploy with a zero verifier and zero root, then turn the gate on later with setZkMembership:
const dao = await MyDao.deploy(TOKEN, ethers.ZeroAddress, ethers.ZeroHash);Deploy your own verifier (custom circuit only)
You only need this if you author your own Noir membership circuit. Cipher ships the verifier,
not the circuit — regenerate the verifier from your circuit (it’s the standard Noir → Solidity
HonkVerifier output), then deploy it. The HonkVerifier links the ZKTranscriptLib library:
// scripts/deployVerifier.ts
import { ethers } from "hardhat";
async function main() {
const lib = await (await ethers.getContractFactory("ZKTranscriptLib")).deploy();
await lib.waitForDeployment();
const HonkVerifier = await ethers.getContractFactory("HonkVerifier", {
libraries: { ZKTranscriptLib: await lib.getAddress() },
});
const verifier = await HonkVerifier.deploy();
await verifier.waitForDeployment();
console.log("ZKTranscriptLib:", await lib.getAddress());
console.log("HonkVerifier:", await verifier.getAddress());
}
main().catch((e) => { console.error(e); process.exitCode = 1; });Then pass that verifier address to your DAO constructor (or setZkMembership).
Reusing the shared verifier only works if you use the bundled circuit. A custom circuit produces a different verification key, so it needs its own verifier.
Environment
# .env
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_ALCHEMY_KEY
PRIVATE_KEY=your_deployer_private_key
VOTES_TOKEN=0xYourConfidentialVotesToken
MEMBERSHIP_ROOT=0xYourPoseidon2RootNetwork support
| Network | Status |
|---|---|
| Sepolia | Available — reusable verifier deployed |
| Ethereum mainnet | Coming soon |
| L2 networks | Planned |
Next steps
- API Reference — full contract interface

