privacy protocol logo
Skip to Content

API Reference

The adapter’s external surface. It extends the confidential Governor (propose / state / execute / …) and adds the membership gate, confidential voting, and result-decryption flow.

import {IPrivateDaoAdapter} from "@privacy-protocol/cipher-contracts/src/DaoToolkit/interface/IPrivateDaoAdapter.sol";

Membership gate

zkMembershipEnabled

function zkMembershipEnabled() external view returns (bool);

Whether the optional ZK gate is on (a verifier is configured).

voteSubmissionVerifier

function voteSubmissionVerifier() external view returns (address);

The Noir verifier, or address(0) when the gate is disabled.

membershipRoot

function membershipRoot() external view returns (bytes32);

The global Poseidon2 membership root, or bytes32(0) when disabled.

nullifierUsed

function nullifierUsed(uint256 proposalId, bytes32 nullifierHash) external view returns (bool);

Whether a nullifier has already been spent on a proposal.

setZkMembership  (owner)

function setZkMembership(address verifier, bytes32 newMembershipRoot) external;

Enable, disable, or reconfigure the gate at runtime. A non-zero verifier + non-zero canonical root enables; address(0) + bytes32(0) disables. Any other combination reverts.

setMembershipRoot  (owner)

function setMembershipRoot(bytes32 newMembershipRoot) external;

Rotate the membership root while the gate is enabled.

Confidential voting

castEncryptedVoteWithMembershipProof

function castEncryptedVoteWithMembershipProof( uint256 proposalId, externalEuint8 support, bytes calldata supportProof, bytes32 nullifierHash, bytes calldata membershipProof ) external returns (euint64);
ParameterDescription
proposalIdThe proposal being voted on
supportEncrypted ballot handle (0 Against / 1 For / 2 Abstain)
supportProofFHE input proof for support
nullifierHashPoseidon2(proposalId mod BN254, identitySecret)
membershipProofSerialized Noir proof for the current membershipRoot

Reverts: PDA__MembershipProofNotEnabled (gate off), PDA__NullifierAlreadyUsed, PDA__InvalidMembershipProof, PDA__FieldElementOutOfRange.

castEncryptedVote

function castEncryptedVote( uint256 proposalId, externalEuint8 support, bytes calldata supportProof ) external returns (euint64);

Plain confidential vote (no membership proof). Reverts with PDA__MembershipProofRequired while the gate is enabled.

proposalVotes

function proposalVotes(uint256 proposalId) external view returns (euint64 againstVotes, euint64 forVotes, euint64 abstainVotes);

The encrypted tally handles. They remain encrypted even after finalization.

Result decryption

requestProposalResultDecryption

function requestProposalResultDecryption(uint256 proposalId) external;

After the deadline, makes the encrypted result booleans publicly decryptable.

encryptedProposalResult

function encryptedProposalResult(uint256 proposalId) external view returns (ebool encryptedQuorumReached, ebool encryptedVoteSucceeded);

finalizeProposalResult

function finalizeProposalResult( uint256 proposalId, bytes memory abiEncodedProposalResult, // abi.encode(bool quorumReached, bool voteSucceeded) bytes memory decryptionProof // KMS proof, re-verified on-chain ) external;

quorumReached / voteSucceeded

function quorumReached(uint256 proposalId) external view returns (bool); function voteSucceeded(uint256 proposalId) external view returns (bool);

Resolve the finalized result. Revert until finalizeProposalResult has run.

Inherited Governor surface

Standard OpenZeppelin Governor functions are available, including:

function propose(address[] targets, uint256[] values, bytes[] calldatas, string description) external returns (uint256 proposalId); function state(uint256 proposalId) external view returns (ProposalState); function proposalSnapshot(uint256 proposalId) external view returns (uint256); function proposalDeadline(uint256 proposalId) external view returns (uint256); function hasVoted(uint256 proposalId, address account) external view returns (bool); function execute(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) external payable returns (uint256 proposalId);

state() reverts with GovernorConfidential__ResultNotFinalized between a proposal’s deadline and finalizeProposalResult.

Events

EventParametersEmitted when
PDA__ZkMembershipConfiguredverifier, membershipRoot, enabledgate (re)configured — constructor or setZkMembership
PDA__MembershipRootUpdatedpreviousRoot, newRootsetMembershipRoot
PDA__MembershipVoteCastproposalId, nullifierHasha membership-gated vote is accepted
EncryptedVoteCastvoter, proposalId, encryptedSupport, weight, reasonany encrypted vote
ProposalResultDecryptionRequestedproposalId, encryptedQuorumReached, encryptedVoteSucceededrequestProposalResultDecryption
ProposalResultFinalizedproposalId, quorumReached, voteSucceededfinalizeProposalResult
ProposalCreatedGovernor-standardpropose

Errors

ErrorCause
PDA__InvalidVerifierVerifier address has no contract code
PDA__InvalidMembershipRootZero/out-of-range root when enabling, or a root supplied without a verifier
PDA__FieldElementOutOfRangeA field element ≥ the BN254 scalar field
PDA__NullifierAlreadyUsedDouble vote — nullifier already spent on this proposal
PDA__InvalidMembershipProofNoir proof failed verification
PDA__MembershipProofRequiredUsed an un-gated entrypoint while the gate is enabled
PDA__MembershipProofNotEnabledUsed a ZK-only function while the gate is disabled

IVotesConfidential (your token)

Your votes token implements this confidential IVotes-style interface:

function getVotes(address account) external view returns (euint64); function getPastVotes(address account, uint256 timepoint) external view returns (euint64); function getPastTotalSupply(uint256 timepoint) external view returns (euint64); function confidentialTotalSupply() external view returns (euint64); function delegates(address account) external view returns (address); function delegate(address delegatee) external;

Off-chain artifacts

The proving kit and member-set artifacts your client produces (see Membership & Proving Kits):

type ProvingKit = { membershipRoot: string; // bytes32, must match on-chain leafIndex: number; leafHash: string; // bytes32 — Poseidon2(identitySecret) identitySecret: string; // bytes32 — PRIVATE siblingPath: string[]; // 32 × bytes32 }; type MemberSet = { membershipRoot: string; // bytes32 leaves: string[]; // ordered; index = leafIndex };
Last updated on