Website: https://zkopengov.org
Privacy-preserving tier-based voting layer for Polkadot OpenGov using ZK-SNARKs.
zkOpenGov enables anonymous voting on OpenGov referenda. Voters register on-chain (identity verified), then cast private votes via Groth16 ZK proofs that prove balance-tier membership without revealing identity or exact balance.
- Register: Connect your Polkadot wallet, generate a secret, and register your commitment on-chain
- Vote: Select a proposal, choose Aye/Nay/Abstain — a ZK proof is generated in your browser proving you belong to a balance tier without revealing your address
- Privacy: Your vote is submitted through a relayer, so your identity is never linked to your vote on-chain
Instead of 1-token-1-vote (which favors whales), votes are weighted by balance tier:
| Tier | Balance Range (DOT) | Vote Weight |
|---|---|---|
| 0 | 1 – 100 | 1 |
| 1 | 100 – 1,000 | 3 |
| 2 | 1,000 – 10,000 | 6 |
| 3 | 10,000 – 100,000 | 10 |
| 4 | 100,000+ | 15 |
A 100k DOT holder gets 15x weight (not 1000x) over a 100 DOT holder.
┌──────────────────┐
│ ZK Circuits │ Circom (Groth16)
│ (Poseidon hash) │
└────────┬─────────┘
│ verifier.sol, WASM, zkey
▼
┌────────┐ ┌───────────┐ ┌────────────┐
│Indexer │→ │ Contracts │←─│Client Lib │
│(trees) │ │(Solidity) │ │(proof gen) │
└────────┘ └─────┬─────┘ └────────────┘
│ │
┌─────┴──────┐ │
│ Relayer │ │
└─────┬──────┘ │
└────────┬───────┘
┌─────┴─────┐
│ Frontend │
│ (React) │
└───────────┘
| Component | Directory | Description |
|---|---|---|
| ZK Circuits | circuits/ |
Circom circuit proving tier membership + vote binding |
| Smart Contracts | contracts/ |
VotingRegistry, VotingBooth, Groth16Verifier |
| Indexing Service | indexer/ |
Builds Poseidon Merkle trees, serves via REST API |
| Client Proof Library | client-lib/ |
Browser-compatible proof generation library |
| Relayer | relayer/ |
Submits votes on behalf of users (gas abstraction) |
| Frontend | frontend/ |
React UI for registration, voting, results |
- Node.js >= 18
- circom 2.x (
npm install -g circom) - snarkjs (
npm install -g snarkjs)
# Install all dependencies
npm install
# Build circuits (critical path)
cd circuits && npm run build
# Compile contracts
cd contracts && npx hardhat compile
# Start indexer (demo mode)
cd indexer && npm run dev
# Start frontend
cd frontend && npm run dev# Circuit tests
cd circuits && npm test
# Contract tests
cd contracts && npx hardhat test
# Indexer tests
cd indexer && npm test
# E2E tests (requires local node)
cd e2e && npm test| Contract | Address |
|---|---|
| Groth16Verifier | 0x1E8139d14c7dE8703dEfB9eAb6aDAdC7B572b8a9 |
| VotingRegistry | 0xC5a08D782CA60Bc69BddE400332bA595543bDc5E |
| VotingBooth | 0xec99cd6cb7B9469B7CA9c918EB6481EDb08aed71 |
- Network: Polkadot Hub Testnet (chain ID 420420417)
- RPC:
https://eth-rpc-testnet.polkadot.io/ - Compiler: resolc 1.0.0 (PolkaVM)
- Registration is public (on-chain) — links your address to a commitment
- Voting is private:
- ZK proof reveals only: tier, vote choice, nullifier (no address)
- Nullifier =
Poseidon(secret, proposalId)— deterministic but unlinkable across proposals - Full tree data is downloaded by all clients (no per-address queries to indexer)
- Proof generation happens entirely in the browser
- Vote submitted through relayer (no address link)
Built for DoraHacks Polkadot Solidity Hackathon (Feb 15 – Mar 24, 2026). Target: Polkadot Hub (pallet-revive EVM).
MIT