Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use mode instead of flag for voting option #1369

Merged
merged 1 commit into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cli/ts/commands/deployPoll.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MACI__factory as MACIFactory } from "maci-contracts";
import { MACI__factory as MACIFactory, EMode } from "maci-contracts";
import { PubKey } from "maci-domainobjs";

import {
Expand Down Expand Up @@ -107,7 +107,7 @@ export const deployPoll = async ({
unserializedKey.asContractParam(),
verifierContractAddress,
vkRegistry,
useQuadraticVoting,
useQuadraticVoting ? EMode.QV : EMode.NON_QV,
{ gasLimit: 10000000 },
);

Expand Down
5 changes: 2 additions & 3 deletions cli/ts/commands/proveOnChain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
Verifier__factory as VerifierFactory,
formatProofForVerifierContract,
type IVerifyingKeyStruct,
EMode,
} from "maci-contracts";
import { STATE_TREE_ARITY } from "maci-core";
import { G1Point, G2Point, hashLeftRight } from "maci-crypto";
Expand Down Expand Up @@ -166,8 +165,8 @@ export const proveOnChain = async ({
}

let numberBatchesProcessed = Number(await mpContract.numBatchesProcessed());
const tallyMode = await tallyContract.isQv().then((isQv) => (isQv ? EMode.QV : EMode.NON_QV));
const mpMode = await mpContract.isQv().then((isQv) => (isQv ? EMode.QV : EMode.NON_QV));
const tallyMode = await tallyContract.mode();
const mpMode = await mpContract.mode();

if (tallyMode !== mpMode) {
logError("Tally and MessageProcessor modes are not compatible");
Expand Down
11 changes: 6 additions & 5 deletions contracts/contracts/MACI.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,202 +12,203 @@
import { Params } from "./utilities/Params.sol";
import { TopupCredit } from "./TopupCredit.sol";
import { Utilities } from "./utilities/Utilities.sol";
import { DomainObjs } from "./utilities/DomainObjs.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

/// @title MACI - Minimum Anti-Collusion Infrastructure Version 1
/// @notice A contract which allows users to sign up, and deploy new polls
contract MACI is IMACI, Params, Utilities, Ownable {
contract MACI is IMACI, DomainObjs, Params, Utilities, Ownable {
/// @notice The state tree depth is fixed. As such it should be as large as feasible
/// so that there can be as many users as possible. i.e. 5 ** 10 = 9765625
/// this should also match the parameter of the circom circuits.
uint8 public immutable stateTreeDepth;

/// @notice IMPORTANT: remember to change the ballot tree depth
/// in contracts/ts/genEmptyBallotRootsContract.ts file
/// if we change the state tree depth!
uint8 internal constant STATE_TREE_SUBDEPTH = 2;
uint8 internal constant TREE_ARITY = 5;

/// @notice The hash of a blank state leaf
uint256 internal constant BLANK_STATE_LEAF_HASH =
uint256(6769006970205099520508948723718471724660867171122235270773600567925038008762);

/// @notice Each poll has an incrementing ID
uint256 public nextPollId;

/// @notice A mapping of poll IDs to Poll contracts.
mapping(uint256 => address) public polls;

/// @notice Whether the subtrees have been merged (can merge root before new signup)
bool public subtreesMerged;

/// @notice The number of signups
uint256 public numSignUps;

/// @notice ERC20 contract that hold topup credits
TopupCredit public immutable topupCredit;

/// @notice Factory contract that deploy a Poll contract
IPollFactory public immutable pollFactory;

/// @notice Factory contract that deploy a MessageProcessor contract
IMessageProcessorFactory public immutable messageProcessorFactory;

/// @notice Factory contract that deploy a Tally contract
ITallyFactory public immutable tallyFactory;

/// @notice The state AccQueue. Represents a mapping between each user's public key
/// and their voice credit balance.
AccQueue public immutable stateAq;

/// @notice Address of the SignUpGatekeeper, a contract which determines whether a
/// user may sign up to vote
SignUpGatekeeper public immutable signUpGatekeeper;

/// @notice The contract which provides the values of the initial voice credit
/// balance per user
InitialVoiceCreditProxy public immutable initialVoiceCreditProxy;

/// @notice A struct holding the addresses of poll, mp and tally
struct PollContracts {
address poll;
address messageProcessor;
address tally;
}

// Events
event SignUp(
uint256 _stateIndex,
uint256 indexed _userPubKeyX,
uint256 indexed _userPubKeyY,
uint256 _voiceCreditBalance,
uint256 _timestamp
);
event DeployPoll(
uint256 _pollId,
uint256 indexed _coordinatorPubKeyX,
uint256 indexed _coordinatorPubKeyY,
PollContracts pollAddr
);

/// @notice Only allow a Poll contract to call the modified function.
modifier onlyPoll(uint256 _pollId) {
if (msg.sender != address(polls[_pollId])) revert CallerMustBePoll(msg.sender);
_;
}

/// @notice custom errors
error CallerMustBePoll(address _caller);
error PoseidonHashLibrariesNotLinked();
error TooManySignups();
error MaciPubKeyLargerThanSnarkFieldSize();
error PreviousPollNotCompleted(uint256 pollId);
error PollDoesNotExist(uint256 pollId);
error SignupTemporaryBlocked();

/// @notice Create a new instance of the MACI contract.
/// @param _pollFactory The PollFactory contract
/// @param _messageProcessorFactory The MessageProcessorFactory contract
/// @param _tallyFactory The TallyFactory contract
/// @param _signUpGatekeeper The SignUpGatekeeper contract
/// @param _initialVoiceCreditProxy The InitialVoiceCreditProxy contract
/// @param _topupCredit The TopupCredit contract
/// @param _stateTreeDepth The depth of the state tree
constructor(
IPollFactory _pollFactory,
IMessageProcessorFactory _messageProcessorFactory,
ITallyFactory _tallyFactory,
SignUpGatekeeper _signUpGatekeeper,
InitialVoiceCreditProxy _initialVoiceCreditProxy,
TopupCredit _topupCredit,
uint8 _stateTreeDepth
) payable {
// Deploy the state AccQueue
stateAq = new AccQueueQuinaryBlankSl(STATE_TREE_SUBDEPTH);
stateAq.enqueue(BLANK_STATE_LEAF_HASH);

// because we add a blank leaf we need to count one signup
// so we don't allow max + 1
unchecked {
numSignUps++;
}

pollFactory = _pollFactory;
messageProcessorFactory = _messageProcessorFactory;
tallyFactory = _tallyFactory;
topupCredit = _topupCredit;
signUpGatekeeper = _signUpGatekeeper;
initialVoiceCreditProxy = _initialVoiceCreditProxy;
stateTreeDepth = _stateTreeDepth;

// Verify linked poseidon libraries
if (hash2([uint256(1), uint256(1)]) == 0) revert PoseidonHashLibrariesNotLinked();
}

/// @notice Allows any eligible user sign up. The sign-up gatekeeper should prevent
/// double sign-ups or ineligible users from doing so. This function will
/// only succeed if the sign-up deadline has not passed. It also enqueues a
/// fresh state leaf into the state AccQueue.
/// @param _pubKey The user's desired public key.
/// @param _signUpGatekeeperData Data to pass to the sign-up gatekeeper's
/// register() function. For instance, the POAPGatekeeper or
/// SignUpTokenGatekeeper requires this value to be the ABI-encoded
/// token ID.
/// @param _initialVoiceCreditProxyData Data to pass to the
/// InitialVoiceCreditProxy, which allows it to determine how many voice
/// credits this user should have.
function signUp(
PubKey memory _pubKey,
bytes memory _signUpGatekeeperData,
bytes memory _initialVoiceCreditProxyData
) public virtual {
// prevent new signups until we merge the roots (possible DoS)
if (subtreesMerged) revert SignupTemporaryBlocked();

// ensure we do not have more signups than what the circuits support
if (numSignUps >= uint256(TREE_ARITY) ** uint256(stateTreeDepth)) revert TooManySignups();

if (_pubKey.x >= SNARK_SCALAR_FIELD || _pubKey.y >= SNARK_SCALAR_FIELD) {
revert MaciPubKeyLargerThanSnarkFieldSize();
}

// Increment the number of signups
// cannot overflow with realistic STATE_TREE_DEPTH
// values as numSignUps < 5 ** STATE_TREE_DEPTH -1
unchecked {
numSignUps++;
}

// Register the user via the sign-up gatekeeper. This function should
// throw if the user has already registered or if ineligible to do so.
signUpGatekeeper.register(msg.sender, _signUpGatekeeperData);

// Get the user's voice credit balance.
uint256 voiceCreditBalance = initialVoiceCreditProxy.getVoiceCredits(msg.sender, _initialVoiceCreditProxyData);

uint256 timestamp = block.timestamp;
// Create a state leaf and enqueue it.
uint256 stateLeaf = hashStateLeaf(StateLeaf(_pubKey, voiceCreditBalance, timestamp));
uint256 stateIndex = stateAq.enqueue(stateLeaf);

emit SignUp(stateIndex, _pubKey.x, _pubKey.y, voiceCreditBalance, timestamp);
}

/// @notice Deploy a new Poll contract.
/// @param _duration How long should the Poll last for
/// @param _treeDepths The depth of the Merkle trees
/// @param _coordinatorPubKey The coordinator's public key
/// @param _verifier The Verifier Contract
/// @param _vkRegistry The VkRegistry Contract
/// @param _isQv Whether to support QV or not
/// @param _mode Voting mode
/// @return pollAddr a new Poll contract address
function deployPoll(
uint256 _duration,
TreeDepths memory _treeDepths,
PubKey memory _coordinatorPubKey,
address _verifier,
address _vkRegistry,
bool _isQv
Mode _mode
Dismissed Show dismissed Hide dismissed
) public virtual onlyOwner returns (PollContracts memory pollAddr) {
// cache the poll to a local variable so we can increment it
uint256 pollId = nextPollId;
Expand Down Expand Up @@ -239,8 +240,8 @@
_owner
);

address mp = messageProcessorFactory.deploy(_verifier, _vkRegistry, p, _owner, _isQv);
address tally = tallyFactory.deploy(_verifier, _vkRegistry, p, mp, _owner, _isQv);
address mp = messageProcessorFactory.deploy(_verifier, _vkRegistry, p, _owner, _mode);
address tally = tallyFactory.deploy(_verifier, _vkRegistry, p, mp, _owner, _mode);

polls[pollId] = p;

Expand Down
12 changes: 6 additions & 6 deletions contracts/contracts/MessageProcessor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,285 +11,285 @@
import { IVkRegistry } from "./interfaces/IVkRegistry.sol";
import { IMessageProcessor } from "./interfaces/IMessageProcessor.sol";
import { CommonUtilities } from "./utilities/CommonUtilities.sol";
import { DomainObjs } from "./utilities/DomainObjs.sol";

/// @title MessageProcessor
/// @dev MessageProcessor is used to process messages published by signup users.
/// It will process message by batch due to large size of messages.
/// After it finishes processing, the sbCommitment will be used for Tally and Subsidy contracts.
contract MessageProcessor is Ownable, SnarkCommon, Hasher, CommonUtilities, IMessageProcessor {
contract MessageProcessor is Ownable, SnarkCommon, Hasher, CommonUtilities, IMessageProcessor, DomainObjs {
/// @notice custom errors
error NoMoreMessages();
error StateAqNotMerged();
error MessageAqNotMerged();
error InvalidProcessMessageProof();
error VkNotSet();
error MaxVoteOptionsTooLarge();
error NumSignUpsTooLarge();
error CurrentMessageBatchIndexTooLarge();
error BatchEndIndexTooLarge();

// the number of children per node in the merkle trees
uint256 internal constant TREE_ARITY = 5;

/// @inheritdoc IMessageProcessor
bool public processingComplete;

/// @notice The number of batches processed
uint256 public numBatchesProcessed;

/// @notice The current message batch index. When the coordinator runs
/// processMessages(), this action relates to messages
/// currentMessageBatchIndex to currentMessageBatchIndex + messageBatchSize.
uint256 public currentMessageBatchIndex;

/// @inheritdoc IMessageProcessor
uint256 public sbCommitment;

IPoll public immutable poll;
IVerifier public immutable verifier;
IVkRegistry public immutable vkRegistry;
bool public immutable isQv;
Mode public immutable mode;

/// @notice Create a new instance
/// @param _verifier The Verifier contract address
/// @param _vkRegistry The VkRegistry contract address
/// @param _poll The Poll contract address
/// @param _isQv Whether to support QV or not
constructor(address _verifier, address _vkRegistry, address _poll, bool _isQv) payable {
/// @param _mode Voting mode
constructor(address _verifier, address _vkRegistry, address _poll, Mode _mode) payable {
verifier = IVerifier(_verifier);
vkRegistry = IVkRegistry(_vkRegistry);
poll = IPoll(_poll);
isQv = _isQv;
mode = _mode;
}

/// @notice Update the Poll's currentSbCommitment if the proof is valid.
/// @param _newSbCommitment The new state root and ballot root commitment
/// after all messages are processed
/// @param _proof The zk-SNARK proof
function processMessages(uint256 _newSbCommitment, uint256[8] memory _proof) external onlyOwner {
// ensure the voting period is over
_votingPeriodOver(poll);

// There must be unprocessed messages
if (processingComplete) {
revert NoMoreMessages();
}

// The state AccQueue must be merged
if (!poll.stateAqMerged()) {
revert StateAqNotMerged();
}

// Retrieve stored vals
(, uint8 messageTreeSubDepth, uint8 messageTreeDepth, uint8 voteOptionTreeDepth) = poll.treeDepths();
// calculate the message batch size from the message tree subdepth
uint256 messageBatchSize = TREE_ARITY ** messageTreeSubDepth;

(, AccQueue messageAq, ) = poll.extContracts();

// Require that the message queue has been merged
uint256 messageRoot = messageAq.getMainRoot(messageTreeDepth);
if (messageRoot == 0) {
revert MessageAqNotMerged();
}

// Copy the state and ballot commitment and set the batch index if this
// is the first batch to process
if (numBatchesProcessed == 0) {
uint256 currentSbCommitment = poll.currentSbCommitment();
sbCommitment = currentSbCommitment;
(, uint256 numMessages) = poll.numSignUpsAndMessages();
uint256 r = numMessages % messageBatchSize;

currentMessageBatchIndex = numMessages;

if (currentMessageBatchIndex > 0) {
if (r == 0) {
currentMessageBatchIndex -= messageBatchSize;
} else {
currentMessageBatchIndex -= r;
}
}
}

if (
!verifyProcessProof(
currentMessageBatchIndex,
messageRoot,
sbCommitment,
_newSbCommitment,
messageTreeSubDepth,
messageTreeDepth,
voteOptionTreeDepth,
_proof
)
) {
revert InvalidProcessMessageProof();
}

{
(, uint256 numMessages) = poll.numSignUpsAndMessages();
// Decrease the message batch start index to ensure that each
// message batch is processed in order
if (currentMessageBatchIndex > 0) {
currentMessageBatchIndex -= messageBatchSize;
}

updateMessageProcessingData(
_newSbCommitment,
currentMessageBatchIndex,
numMessages <= messageBatchSize * (numBatchesProcessed + 1)
);
}
}

/// @notice Verify the proof for processMessage
/// @dev used to update the sbCommitment
/// @param _currentMessageBatchIndex The batch index of current message batch
/// @param _messageRoot The message tree root
/// @param _currentSbCommitment The current sbCommitment (state and ballot)
/// @param _newSbCommitment The new sbCommitment after we update this message batch
/// @param _messageTreeSubDepth The message tree subdepth
/// @param _messageTreeDepth The message tree depth
/// @param _voteOptionTreeDepth The vote option tree depth
/// @param _proof The zk-SNARK proof
/// @return isValid Whether the proof is valid
function verifyProcessProof(
uint256 _currentMessageBatchIndex,
uint256 _messageRoot,
uint256 _currentSbCommitment,
uint256 _newSbCommitment,
uint8 _messageTreeSubDepth,
uint8 _messageTreeDepth,
uint8 _voteOptionTreeDepth,
uint256[8] memory _proof
) internal view returns (bool isValid) {
// get the tree depths
// get the message batch size from the message tree subdepth
// get the number of signups
(uint256 numSignUps, uint256 numMessages) = poll.numSignUpsAndMessages();
(IMACI maci, , ) = poll.extContracts();

// Calculate the public input hash (a SHA256 hash of several values)
uint256 publicInputHash = genProcessMessagesPublicInputHash(
_currentMessageBatchIndex,
_messageRoot,
numSignUps,
numMessages,
_currentSbCommitment,
_newSbCommitment,
_messageTreeSubDepth,
_voteOptionTreeDepth
);

// Get the verifying key from the VkRegistry
IVkRegistry.Mode mode = isQv ? IVkRegistry.Mode.QV : IVkRegistry.Mode.NON_QV;
VerifyingKey memory vk = vkRegistry.getProcessVk(
maci.stateTreeDepth(),
_messageTreeDepth,
_voteOptionTreeDepth,
TREE_ARITY ** _messageTreeSubDepth,
mode
);

isValid = verifier.verify(_proof, vk, publicInputHash);
}

/// @notice Returns the SHA256 hash of the packed values (see
/// genProcessMessagesPackedVals), the hash of the coordinator's public key,
/// the message root, and the commitment to the current state root and
/// ballot root. By passing the SHA256 hash of these values to the circuit
/// as a single public input and the preimage as private inputs, we reduce
/// its verification gas cost though the number of constraints will be
/// higher and proving time will be longer.
/// @param _currentMessageBatchIndex The batch index of current message batch
/// @param _numSignUps The number of users that signup
/// @param _numMessages The number of messages
/// @param _currentSbCommitment The current sbCommitment (state and ballot root)
/// @param _newSbCommitment The new sbCommitment after we update this message batch
/// @param _messageTreeSubDepth The message tree subdepth
/// @return inputHash Returns the SHA256 hash of the packed values
function genProcessMessagesPublicInputHash(
uint256 _currentMessageBatchIndex,
uint256 _messageRoot,
uint256 _numSignUps,
uint256 _numMessages,
uint256 _currentSbCommitment,
uint256 _newSbCommitment,
uint8 _messageTreeSubDepth,
uint8 _voteOptionTreeDepth
) public view returns (uint256 inputHash) {
uint256 coordinatorPubKeyHash = poll.coordinatorPubKeyHash();

// pack the values
uint256 packedVals = genProcessMessagesPackedVals(
_currentMessageBatchIndex,
_numSignUps,
_numMessages,
_messageTreeSubDepth,
_voteOptionTreeDepth
);

(uint256 deployTime, uint256 duration) = poll.getDeployTimeAndDuration();

// generate the circuit only public input
uint256[] memory input = new uint256[](6);
input[0] = packedVals;
input[1] = coordinatorPubKeyHash;
input[2] = _messageRoot;
input[3] = _currentSbCommitment;
input[4] = _newSbCommitment;
input[5] = deployTime + duration;
inputHash = sha256Hash(input);
}

/// @notice One of the inputs to the ProcessMessages circuit is a 250-bit
/// representation of four 50-bit values. This function generates this
/// 250-bit value, which consists of the maximum number of vote options, the
/// number of signups, the current message batch index, and the end index of
/// the current batch.
/// @param _currentMessageBatchIndex batch index of current message batch
/// @param _numSignUps number of users that signup
/// @param _numMessages number of messages
/// @param _messageTreeSubDepth message tree subdepth
/// @param _voteOptionTreeDepth vote option tree depth
/// @return result The packed value
function genProcessMessagesPackedVals(
uint256 _currentMessageBatchIndex,
uint256 _numSignUps,
uint256 _numMessages,
uint8 _messageTreeSubDepth,
uint8 _voteOptionTreeDepth
) public pure returns (uint256 result) {
uint256 maxVoteOptions = TREE_ARITY ** _voteOptionTreeDepth;

// calculate the message batch size from the message tree subdepth
uint256 messageBatchSize = TREE_ARITY ** _messageTreeSubDepth;
uint256 batchEndIndex = _currentMessageBatchIndex + messageBatchSize;
if (batchEndIndex > _numMessages) {
batchEndIndex = _numMessages;
}

if (maxVoteOptions >= 2 ** 50) revert MaxVoteOptionsTooLarge();
if (_numSignUps >= 2 ** 50) revert NumSignUpsTooLarge();
if (_currentMessageBatchIndex >= 2 ** 50) revert CurrentMessageBatchIndexTooLarge();
if (batchEndIndex >= 2 ** 50) revert BatchEndIndexTooLarge();

result = maxVoteOptions + (_numSignUps << 50) + (_currentMessageBatchIndex << 100) + (batchEndIndex << 150);
}

/// @notice update message processing state variables
/// @param _newSbCommitment sbCommitment to be updated
/// @param _currentMessageBatchIndex currentMessageBatchIndex to be updated
/// @param _processingComplete update flag that indicate processing is finished or not
function updateMessageProcessingData(
uint256 _newSbCommitment,
uint256 _currentMessageBatchIndex,
bool _processingComplete
) internal {
sbCommitment = _newSbCommitment;
processingComplete = _processingComplete;
currentMessageBatchIndex = _currentMessageBatchIndex;
numBatchesProcessed++;
}
}

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract MessageProcessor has payable functions:
- MessageProcessor.constructor(address,address,address,address,DomainObjs.Mode)
But does not have a function to withdraw the ether
4 changes: 2 additions & 2 deletions contracts/contracts/MessageProcessorFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
address _vkRegistry,
address _poll,
address _owner,
bool _isQv
Mode _mode
Dismissed Show dismissed Hide dismissed
) public returns (address messageProcessorAddr) {
// deploy MessageProcessor for this Poll
MessageProcessor messageProcessor = new MessageProcessor(_verifier, _vkRegistry, _poll, _isQv);
MessageProcessor messageProcessor = new MessageProcessor(_verifier, _vkRegistry, _poll, _mode);
messageProcessor.transferOwnership(_owner);
messageProcessorAddr = address(messageProcessor);
}
Expand Down
24 changes: 13 additions & 11 deletions contracts/contracts/Tally.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,364 +10,366 @@
import { IVerifier } from "./interfaces/IVerifier.sol";
import { IVkRegistry } from "./interfaces/IVkRegistry.sol";
import { CommonUtilities } from "./utilities/CommonUtilities.sol";
import { DomainObjs } from "./utilities/DomainObjs.sol";

/// @title Tally
/// @notice The Tally contract is used during votes tallying
/// and by users to verify the tally results.
contract Tally is Ownable, SnarkCommon, CommonUtilities, Hasher {
contract Tally is Ownable, SnarkCommon, CommonUtilities, Hasher, DomainObjs {
uint256 internal constant TREE_ARITY = 5;

/// @notice The commitment to the tally results. Its initial value is 0, but after
/// the tally of each batch is proven on-chain via a zk-SNARK, it should be
/// updated to:
///
/// QV:
/// hash3(
/// hashLeftRight(merkle root of current results, salt0)
/// hashLeftRight(number of spent voice credits, salt1),
/// hashLeftRight(merkle root of the no. of spent voice credits per vote option, salt2)
/// )
///
/// Non-QV:
/// hash2(
/// hashLeftRight(merkle root of current results, salt0)
/// hashLeftRight(number of spent voice credits, salt1),
/// )
///
/// Where each salt is unique and the merkle roots are of arrays of leaves
/// TREE_ARITY ** voteOptionTreeDepth long.
uint256 public tallyCommitment;

uint256 public tallyBatchNum;

// The final commitment to the state and ballot roots
uint256 public sbCommitment;

IVerifier public immutable verifier;
IVkRegistry public immutable vkRegistry;
IPoll public immutable poll;
IMessageProcessor public immutable messageProcessor;
bool public immutable isQv;
Mode public immutable mode;

/// @notice custom errors
error ProcessingNotComplete();
error InvalidTallyVotesProof();
error AllBallotsTallied();
error NumSignUpsTooLarge();
error BatchStartIndexTooLarge();
error TallyBatchSizeTooLarge();
error NotSupported();

/// @notice Create a new Tally contract
/// @param _verifier The Verifier contract
/// @param _vkRegistry The VkRegistry contract
/// @param _poll The Poll contract
/// @param _mp The MessageProcessor contract
constructor(address _verifier, address _vkRegistry, address _poll, address _mp, bool _isQv) payable {
constructor(address _verifier, address _vkRegistry, address _poll, address _mp, Mode _mode) payable {
verifier = IVerifier(_verifier);
vkRegistry = IVkRegistry(_vkRegistry);
poll = IPoll(_poll);
messageProcessor = IMessageProcessor(_mp);
isQv = _isQv;
mode = _mode;
}

/// @notice Pack the batch start index and number of signups into a 100-bit value.
/// @param _numSignUps: number of signups
/// @param _batchStartIndex: the start index of given batch
/// @param _tallyBatchSize: size of batch
/// @return result an uint256 representing the 3 inputs packed together
function genTallyVotesPackedVals(
uint256 _numSignUps,
uint256 _batchStartIndex,
uint256 _tallyBatchSize
) public pure returns (uint256 result) {
if (_numSignUps >= 2 ** 50) revert NumSignUpsTooLarge();
if (_batchStartIndex >= 2 ** 50) revert BatchStartIndexTooLarge();
if (_tallyBatchSize >= 2 ** 50) revert TallyBatchSizeTooLarge();

result = (_batchStartIndex / _tallyBatchSize) + (_numSignUps << uint256(50));
}

/// @notice Check if all ballots are tallied
/// @return tallied whether all ballots are tallied
function isTallied() public view returns (bool tallied) {
(uint8 intStateTreeDepth, , , ) = poll.treeDepths();
(uint256 numSignUps, ) = poll.numSignUpsAndMessages();

// Require that there are untallied ballots left
tallied = tallyBatchNum * (TREE_ARITY ** intStateTreeDepth) >= numSignUps;
}

/// @notice generate hash of public inputs for tally circuit
/// @param _numSignUps: number of signups
/// @param _batchStartIndex: the start index of given batch
/// @param _tallyBatchSize: size of batch
/// @param _newTallyCommitment: the new tally commitment to be updated
/// @return inputHash hash of public inputs
function genTallyVotesPublicInputHash(
uint256 _numSignUps,
uint256 _batchStartIndex,
uint256 _tallyBatchSize,
uint256 _newTallyCommitment
) public view returns (uint256 inputHash) {
uint256 packedVals = genTallyVotesPackedVals(_numSignUps, _batchStartIndex, _tallyBatchSize);
uint256[] memory input = new uint256[](4);
input[0] = packedVals;
input[1] = sbCommitment;
input[2] = tallyCommitment;
input[3] = _newTallyCommitment;
inputHash = sha256Hash(input);
}

/// @notice Update the state and ballot root commitment
function updateSbCommitment() public onlyOwner {
// Require that all messages have been processed
if (!messageProcessor.processingComplete()) {
revert ProcessingNotComplete();
}

if (sbCommitment == 0) {
sbCommitment = messageProcessor.sbCommitment();
}
}

/// @notice Verify the result of a tally batch
/// @param _newTallyCommitment the new tally commitment to be verified
/// @param _proof the proof generated after tallying this batch
function tallyVotes(uint256 _newTallyCommitment, uint256[8] calldata _proof) public onlyOwner {
_votingPeriodOver(poll);
updateSbCommitment();

// get the batch size and start index
(uint8 intStateTreeDepth, , , ) = poll.treeDepths();
uint256 tallyBatchSize = TREE_ARITY ** intStateTreeDepth;
uint256 batchStartIndex = tallyBatchNum * tallyBatchSize;

// save some gas because we won't overflow uint256
unchecked {
tallyBatchNum++;
}

(uint256 numSignUps, ) = poll.numSignUpsAndMessages();

// Require that there are untallied ballots left
if (batchStartIndex >= numSignUps) {
revert AllBallotsTallied();
}

bool isValid = verifyTallyProof(_proof, numSignUps, batchStartIndex, tallyBatchSize, _newTallyCommitment);

if (!isValid) {
revert InvalidTallyVotesProof();
}

// Update the tally commitment and the tally batch num
tallyCommitment = _newTallyCommitment;
}

/// @notice Verify the tally proof using the verifying key
/// @param _proof the proof generated after processing all messages
/// @param _numSignUps number of signups for a given poll
/// @param _batchStartIndex the number of batches multiplied by the size of the batch
/// @param _tallyBatchSize batch size for the tally
/// @param _newTallyCommitment the tally commitment to be verified at a given batch index
/// @return isValid whether the proof is valid
function verifyTallyProof(
uint256[8] calldata _proof,
uint256 _numSignUps,
uint256 _batchStartIndex,
uint256 _tallyBatchSize,
uint256 _newTallyCommitment
) public view returns (bool isValid) {
(uint8 intStateTreeDepth, , , uint8 voteOptionTreeDepth) = poll.treeDepths();

(IMACI maci, , ) = poll.extContracts();

// Get the verifying key
IVkRegistry.Mode mode = isQv ? IVkRegistry.Mode.QV : IVkRegistry.Mode.NON_QV;
VerifyingKey memory vk = vkRegistry.getTallyVk(maci.stateTreeDepth(), intStateTreeDepth, voteOptionTreeDepth, mode);

// Get the public inputs
uint256 publicInputHash = genTallyVotesPublicInputHash(
_numSignUps,
_batchStartIndex,
_tallyBatchSize,
_newTallyCommitment
);

// Verify the proof
isValid = verifier.verify(_proof, vk, publicInputHash);
}

/// @notice Compute the merkle root from the path elements
/// and a leaf
/// @param _depth the depth of the merkle tree
/// @param _index the index of the leaf
/// @param _leaf the leaf
/// @param _pathElements the path elements to reconstruct the merkle root
/// @return current The merkle root
function computeMerkleRootFromPath(
uint8 _depth,
uint256 _index,
uint256 _leaf,
uint256[][] calldata _pathElements
) internal pure returns (uint256 current) {
uint256 pos = _index % TREE_ARITY;
current = _leaf;
uint8 k;

uint256[TREE_ARITY] memory level;

for (uint8 i = 0; i < _depth; ++i) {
for (uint8 j = 0; j < TREE_ARITY; ++j) {
if (j == pos) {
level[j] = current;
} else {
if (j > pos) {
k = j - 1;
} else {
k = j;
}
level[j] = _pathElements[i][k];
}
}

_index /= TREE_ARITY;
pos = _index % TREE_ARITY;
current = hash5(level);
}
}

/// @notice Verify the number of spent voice credits from the tally.json
/// @param _totalSpent spent field retrieved in the totalSpentVoiceCredits object
/// @param _totalSpentSalt the corresponding salt in the totalSpentVoiceCredit object
/// @param _resultCommitment hashLeftRight(merkle root of the results.tally, results.salt) in tally.json file
/// @param _perVOSpentVoiceCreditsHash only for QV - hashLeftRight(merkle root of the no spent voice credits, salt)
/// @return isValid Whether the provided values are valid
function verifySpentVoiceCredits(
uint256 _totalSpent,
uint256 _totalSpentSalt,
uint256 _resultCommitment,
uint256 _perVOSpentVoiceCreditsHash
) public view returns (bool isValid) {
uint256[3] memory tally;
tally[0] = _resultCommitment;
tally[1] = hashLeftRight(_totalSpent, _totalSpentSalt);
tally[2] = _perVOSpentVoiceCreditsHash;

isValid = isQv
? verifyQvSpentVoiceCredits(_totalSpent, _totalSpentSalt, _resultCommitment, _perVOSpentVoiceCreditsHash)
: verifyNonQvSpentVoiceCredits(_totalSpent, _totalSpentSalt, _resultCommitment);
if (mode == Mode.QV) {
isValid = verifyQvSpentVoiceCredits(_totalSpent, _totalSpentSalt, _resultCommitment, _perVOSpentVoiceCreditsHash);
} else if (mode == Mode.NON_QV) {
isValid = verifyNonQvSpentVoiceCredits(_totalSpent, _totalSpentSalt, _resultCommitment);
}
}

/// @notice Verify the number of spent voice credits for QV from the tally.json
/// @param _totalSpent spent field retrieved in the totalSpentVoiceCredits object
/// @param _totalSpentSalt the corresponding salt in the totalSpentVoiceCredit object
/// @param _resultCommitment hashLeftRight(merkle root of the results.tally, results.salt) in tally.json file
/// @param _perVOSpentVoiceCreditsHash hashLeftRight(merkle root of the no spent voice credits per vote option, salt)
/// @return isValid Whether the provided values are valid
function verifyQvSpentVoiceCredits(
uint256 _totalSpent,
uint256 _totalSpentSalt,
uint256 _resultCommitment,
uint256 _perVOSpentVoiceCreditsHash
) internal view returns (bool isValid) {
uint256[3] memory tally;
tally[0] = _resultCommitment;
tally[1] = hashLeftRight(_totalSpent, _totalSpentSalt);
tally[2] = _perVOSpentVoiceCreditsHash;

isValid = hash3(tally) == tallyCommitment;
}

/// @notice Verify the number of spent voice credits for Non-QV from the tally.json
/// @param _totalSpent spent field retrieved in the totalSpentVoiceCredits object
/// @param _totalSpentSalt the corresponding salt in the totalSpentVoiceCredit object
/// @param _resultCommitment hashLeftRight(merkle root of the results.tally, results.salt) in tally.json file
/// @return isValid Whether the provided values are valid
function verifyNonQvSpentVoiceCredits(
uint256 _totalSpent,
uint256 _totalSpentSalt,
uint256 _resultCommitment
) internal view returns (bool isValid) {
uint256[2] memory tally;
tally[0] = _resultCommitment;
tally[1] = hashLeftRight(_totalSpent, _totalSpentSalt);

isValid = hash2(tally) == tallyCommitment;
}

/// @notice Verify the number of spent voice credits per vote option from the tally.json
/// @param _voteOptionIndex the index of the vote option where credits were spent
/// @param _spent the spent voice credits for a given vote option index
/// @param _spentProof proof generated for the perVOSpentVoiceCredits
/// @param _spentSalt the corresponding salt given in the tally perVOSpentVoiceCredits object
/// @param _voteOptionTreeDepth depth of the vote option tree
/// @param _spentVoiceCreditsHash hashLeftRight(number of spent voice credits, spent salt)
/// @param _resultCommitment hashLeftRight(merkle root of the results.tally, results.salt)
// in the tally.json file
/// @return isValid Whether the provided proof is valid
function verifyPerVOSpentVoiceCredits(
uint256 _voteOptionIndex,
uint256 _spent,
uint256[][] calldata _spentProof,
uint256 _spentSalt,
uint8 _voteOptionTreeDepth,
uint256 _spentVoiceCreditsHash,
uint256 _resultCommitment
) public view returns (bool isValid) {
if (!isQv) {
if (mode != Mode.QV) {
revert NotSupported();
}

uint256 computedRoot = computeMerkleRootFromPath(_voteOptionTreeDepth, _voteOptionIndex, _spent, _spentProof);

uint256[3] memory tally;
tally[0] = _resultCommitment;
tally[1] = _spentVoiceCreditsHash;
tally[2] = hashLeftRight(computedRoot, _spentSalt);

isValid = hash3(tally) == tallyCommitment;
}

/// @notice Verify the result generated from the tally.json
/// @param _voteOptionIndex the index of the vote option to verify the correctness of the tally
/// @param _tallyResult Flattened array of the tally
/// @param _tallyResultProof Corresponding proof of the tally result
/// @param _tallyResultSalt the respective salt in the results object in the tally.json
/// @param _voteOptionTreeDepth depth of the vote option tree
/// @param _spentVoiceCreditsHash hashLeftRight(number of spent voice credits, spent salt)
/// @param _perVOSpentVoiceCreditsHash hashLeftRight(merkle root of the no spent voice
/// credits per vote option, perVOSpentVoiceCredits salt)
/// @return isValid Whether the provided proof is valid
function verifyTallyResult(
uint256 _voteOptionIndex,
uint256 _tallyResult,
uint256[][] calldata _tallyResultProof,
uint256 _tallyResultSalt,
uint8 _voteOptionTreeDepth,
uint256 _spentVoiceCreditsHash,
uint256 _perVOSpentVoiceCreditsHash
) public view returns (bool isValid) {
uint256 computedRoot = computeMerkleRootFromPath(
_voteOptionTreeDepth,
_voteOptionIndex,
_tallyResult,
_tallyResultProof
);

if (isQv) {
if (mode == Mode.QV) {
uint256[3] memory tally = [
hashLeftRight(computedRoot, _tallyResultSalt),
_spentVoiceCreditsHash,
_perVOSpentVoiceCreditsHash
];

isValid = hash3(tally) == tallyCommitment;
} else {
} else if (mode == Mode.NON_QV) {
uint256[2] memory tally = [hashLeftRight(computedRoot, _tallyResultSalt), _spentVoiceCreditsHash];

isValid = hash2(tally) == tallyCommitment;
}
}
}

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract Tally has payable functions:
- Tally.constructor(address,address,address,address,address,DomainObjs.Mode)
But does not have a function to withdraw the ether
7 changes: 4 additions & 3 deletions contracts/contracts/TallyFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@

import { Tally } from "./Tally.sol";
import { ITallyFactory } from "./interfaces/ITallyFactory.sol";
import { DomainObjs } from "./utilities/DomainObjs.sol";

/// @title TallyFactory
/// @notice A factory contract which deploys Tally contracts.
contract TallyFactory is ITallyFactory {
contract TallyFactory is ITallyFactory, DomainObjs {
/// @inheritdoc ITallyFactory
function deploy(
address _verifier,
address _vkRegistry,
address _poll,
address _messageProcessor,
address _owner,
bool _isQv
Mode _mode
Dismissed Show dismissed Hide dismissed
) public virtual returns (address tallyAddr) {
// deploy Tally for this Poll
Tally tally = new Tally(_verifier, _vkRegistry, _poll, _messageProcessor, _isQv);
Tally tally = new Tally(_verifier, _vkRegistry, _poll, _messageProcessor, _mode);
tally.transferOwnership(_owner);
tallyAddr = address(tally);
}
Expand Down
7 changes: 4 additions & 3 deletions contracts/contracts/VkRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,252 +4,253 @@
import { SnarkCommon } from "./crypto/SnarkCommon.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IVkRegistry } from "./interfaces/IVkRegistry.sol";
import { DomainObjs } from "./utilities/DomainObjs.sol";

/// @title VkRegistry
/// @notice Stores verifying keys for the circuits.
/// Each circuit has a signature which is its compile-time constants represented
/// as a uint256.
contract VkRegistry is Ownable, SnarkCommon, IVkRegistry {
contract VkRegistry is Ownable, DomainObjs, SnarkCommon, IVkRegistry {
mapping(Mode => mapping(uint256 => VerifyingKey)) internal processVks;
mapping(Mode => mapping(uint256 => bool)) internal processVkSet;

mapping(Mode => mapping(uint256 => VerifyingKey)) internal tallyVks;
mapping(Mode => mapping(uint256 => bool)) internal tallyVkSet;

event ProcessVkSet(uint256 _sig, Mode mode);
event TallyVkSet(uint256 _sig, Mode mode);
event ProcessVkSet(uint256 _sig, Mode _mode);
event TallyVkSet(uint256 _sig, Mode _mode);

error ProcessVkAlreadySet();
error TallyVkAlreadySet();
error ProcessVkNotSet();
error TallyVkNotSet();
error SubsidyVkNotSet();
error InvalidKeysParams();

/// @notice Create a new instance of the VkRegistry contract
// solhint-disable-next-line no-empty-blocks
constructor() payable {}

/// @notice Check if the process verifying key is set
/// @param _sig The signature
/// @param _mode QV or Non-QV
/// @return isSet whether the verifying key is set
function isProcessVkSet(uint256 _sig, Mode _mode) public view returns (bool isSet) {
isSet = processVkSet[_mode][_sig];
}

/// @notice Check if the tally verifying key is set
/// @param _sig The signature
/// @param _mode QV or Non-QV
/// @return isSet whether the verifying key is set
function isTallyVkSet(uint256 _sig, Mode _mode) public view returns (bool isSet) {
isSet = tallyVkSet[_mode][_sig];
}

/// @notice generate the signature for the process verifying key
/// @param _stateTreeDepth The state tree depth
/// @param _messageTreeDepth The message tree depth
/// @param _voteOptionTreeDepth The vote option tree depth
/// @param _messageBatchSize The message batch size
function genProcessVkSig(
uint256 _stateTreeDepth,
uint256 _messageTreeDepth,
uint256 _voteOptionTreeDepth,
uint256 _messageBatchSize
) public pure returns (uint256 sig) {
sig = (_messageBatchSize << 192) + (_stateTreeDepth << 128) + (_messageTreeDepth << 64) + _voteOptionTreeDepth;
}

/// @notice generate the signature for the tally verifying key
/// @param _stateTreeDepth The state tree depth
/// @param _intStateTreeDepth The intermediate state tree depth
/// @param _voteOptionTreeDepth The vote option tree depth
/// @return sig The signature
function genTallyVkSig(
uint256 _stateTreeDepth,
uint256 _intStateTreeDepth,
uint256 _voteOptionTreeDepth
) public pure returns (uint256 sig) {
sig = (_stateTreeDepth << 128) + (_intStateTreeDepth << 64) + _voteOptionTreeDepth;
}

/// @notice Set the process and tally verifying keys for a certain combination
/// of parameters and modes
/// @param _stateTreeDepth The state tree depth
/// @param _intStateTreeDepth The intermediate state tree depth
/// @param _messageTreeDepth The message tree depth
/// @param _voteOptionTreeDepth The vote option tree depth
/// @param _messageBatchSize The message batch size
/// @param _modes Array of QV or Non-QV modes (must have the same length as process and tally keys)
/// @param _processVks The process verifying keys (must have the same length as modes)
/// @param _tallyVks The tally verifying keys (must have the same length as modes)
function setVerifyingKeysBatch(
uint256 _stateTreeDepth,
uint256 _intStateTreeDepth,
uint256 _messageTreeDepth,
uint256 _voteOptionTreeDepth,
uint256 _messageBatchSize,
Mode[] calldata _modes,
VerifyingKey[] calldata _processVks,
VerifyingKey[] calldata _tallyVks
) public onlyOwner {
if (_modes.length != _processVks.length || _modes.length != _tallyVks.length) {
revert InvalidKeysParams();
}

uint256 length = _modes.length;

for (uint256 index = 0; index < length; ) {
setVerifyingKeys(
_stateTreeDepth,
_intStateTreeDepth,
_messageTreeDepth,
_voteOptionTreeDepth,
_messageBatchSize,
_modes[index],
_processVks[index],
_tallyVks[index]
);

unchecked {
index++;
}
}
}

/// @notice Set the process and tally verifying keys for a certain combination
/// of parameters
/// @param _stateTreeDepth The state tree depth
/// @param _intStateTreeDepth The intermediate state tree depth
/// @param _messageTreeDepth The message tree depth
/// @param _voteOptionTreeDepth The vote option tree depth
/// @param _messageBatchSize The message batch size
/// @param _mode QV or Non-QV
/// @param _processVk The process verifying key
/// @param _tallyVk The tally verifying key
function setVerifyingKeys(
uint256 _stateTreeDepth,
uint256 _intStateTreeDepth,
uint256 _messageTreeDepth,
uint256 _voteOptionTreeDepth,
uint256 _messageBatchSize,
Mode _mode,
VerifyingKey calldata _processVk,
VerifyingKey calldata _tallyVk
) public onlyOwner {
uint256 processVkSig = genProcessVkSig(_stateTreeDepth, _messageTreeDepth, _voteOptionTreeDepth, _messageBatchSize);

if (processVkSet[_mode][processVkSig]) revert ProcessVkAlreadySet();

uint256 tallyVkSig = genTallyVkSig(_stateTreeDepth, _intStateTreeDepth, _voteOptionTreeDepth);

if (tallyVkSet[_mode][tallyVkSig]) revert TallyVkAlreadySet();

VerifyingKey storage processVk = processVks[_mode][processVkSig];
processVk.alpha1 = _processVk.alpha1;
processVk.beta2 = _processVk.beta2;
processVk.gamma2 = _processVk.gamma2;
processVk.delta2 = _processVk.delta2;

for (uint8 i = 0; i < _processVk.ic.length; i++) {
processVk.ic.push(_processVk.ic[i]);
}

processVkSet[_mode][processVkSig] = true;

VerifyingKey storage tallyVk = tallyVks[_mode][tallyVkSig];
tallyVk.alpha1 = _tallyVk.alpha1;
tallyVk.beta2 = _tallyVk.beta2;
tallyVk.gamma2 = _tallyVk.gamma2;
tallyVk.delta2 = _tallyVk.delta2;

for (uint8 i = 0; i < _tallyVk.ic.length; i++) {
tallyVk.ic.push(_tallyVk.ic[i]);
}

tallyVkSet[_mode][tallyVkSig] = true;

emit TallyVkSet(tallyVkSig, _mode);
emit ProcessVkSet(processVkSig, _mode);
}

/// @notice Check if the process verifying key is set
/// @param _stateTreeDepth The state tree depth
/// @param _messageTreeDepth The message tree depth
/// @param _voteOptionTreeDepth The vote option tree depth
/// @param _messageBatchSize The message batch size
/// @param _mode QV or Non-QV
/// @return isSet whether the verifying key is set
function hasProcessVk(
uint256 _stateTreeDepth,
uint256 _messageTreeDepth,
uint256 _voteOptionTreeDepth,
uint256 _messageBatchSize,
Mode _mode
) public view returns (bool isSet) {
uint256 sig = genProcessVkSig(_stateTreeDepth, _messageTreeDepth, _voteOptionTreeDepth, _messageBatchSize);
isSet = processVkSet[_mode][sig];
}

/// @notice Get the process verifying key by signature
/// @param _sig The signature
/// @param _mode QV or Non-QV
/// @return vk The verifying key
function getProcessVkBySig(uint256 _sig, Mode _mode) public view returns (VerifyingKey memory vk) {
if (!processVkSet[_mode][_sig]) revert ProcessVkNotSet();

vk = processVks[_mode][_sig];
}

/// @inheritdoc IVkRegistry
function getProcessVk(
uint256 _stateTreeDepth,
uint256 _messageTreeDepth,
uint256 _voteOptionTreeDepth,
uint256 _messageBatchSize,
Mode _mode
) public view returns (VerifyingKey memory vk) {
uint256 sig = genProcessVkSig(_stateTreeDepth, _messageTreeDepth, _voteOptionTreeDepth, _messageBatchSize);

vk = getProcessVkBySig(sig, _mode);
}

/// @notice Check if the tally verifying key is set
/// @param _stateTreeDepth The state tree depth
/// @param _intStateTreeDepth The intermediate state tree depth
/// @param _voteOptionTreeDepth The vote option tree depth
/// @param _mode QV or Non-QV
/// @return isSet whether the verifying key is set
function hasTallyVk(
uint256 _stateTreeDepth,
uint256 _intStateTreeDepth,
uint256 _voteOptionTreeDepth,
Mode _mode
) public view returns (bool isSet) {
uint256 sig = genTallyVkSig(_stateTreeDepth, _intStateTreeDepth, _voteOptionTreeDepth);

isSet = tallyVkSet[_mode][sig];
}

/// @notice Get the tally verifying key by signature
/// @param _sig The signature
/// @param _mode QV or Non-QV
/// @return vk The verifying key
function getTallyVkBySig(uint256 _sig, Mode _mode) public view returns (VerifyingKey memory vk) {
if (!tallyVkSet[_mode][_sig]) revert TallyVkNotSet();

vk = tallyVks[_mode][_sig];
}

/// @inheritdoc IVkRegistry
function getTallyVk(
uint256 _stateTreeDepth,
uint256 _intStateTreeDepth,
uint256 _voteOptionTreeDepth,
Mode _mode
) public view returns (VerifyingKey memory vk) {
uint256 sig = genTallyVkSig(_stateTreeDepth, _intStateTreeDepth, _voteOptionTreeDepth);

vk = getTallyVkBySig(sig, _mode);
}
}

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract VkRegistry has payable functions:
- VkRegistry.constructor()
But does not have a function to withdraw the ether
6 changes: 4 additions & 2 deletions contracts/contracts/interfaces/IMPFactory.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import { DomainObjs } from "../utilities/DomainObjs.sol";

/// @title IMessageProcessorFactory
/// @notice MessageProcessorFactory interface
interface IMessageProcessorFactory {
Expand All @@ -9,13 +11,13 @@ interface IMessageProcessorFactory {
/// @param _vkRegistry VkRegistry contract
/// @param _poll Poll contract
/// @param _owner Owner of the MessageProcessor contract
/// @param _isQv Whether to support QV or not
/// @param _mode Voting mode
/// @return The deployed MessageProcessor contract
function deploy(
address _verifier,
address _vkRegistry,
address _poll,
address _owner,
bool _isQv
DomainObjs.Mode _mode
) external returns (address);
}
6 changes: 4 additions & 2 deletions contracts/contracts/interfaces/ITallyFactory.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import { DomainObjs } from "../utilities/DomainObjs.sol";

/// @title ITallyFactory
/// @notice TallyFactory interface
interface ITallyFactory {
Expand All @@ -10,14 +12,14 @@ interface ITallyFactory {
/// @param _poll Poll contract
/// @param _messageProcessor MessageProcessor contract
/// @param _owner Owner of the contract
/// @param _isQv Whether to support QV or not
/// @param _mode Voting mode
/// @return The deployed contract
function deploy(
address _verifier,
address _vkRegistry,
address _poll,
address _messageProcessor,
address _owner,
bool _isQv
DomainObjs.Mode _mode
) external returns (address);
}
11 changes: 3 additions & 8 deletions contracts/contracts/interfaces/IVkRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@
pragma solidity ^0.8.10;

import { SnarkCommon } from "../crypto/SnarkCommon.sol";
import { DomainObjs } from "../utilities/DomainObjs.sol";

/// @title IVkRegistry
/// @notice VkRegistry interface
interface IVkRegistry {
/// @notice Multi store support for QV and Non-QV poll
enum Mode {
QV,
NON_QV
}

/// @notice Get the tally verifying key
/// @param _stateTreeDepth The state tree depth
/// @param _intStateTreeDepth The intermediate state tree depth
Expand All @@ -22,7 +17,7 @@ interface IVkRegistry {
uint256 _stateTreeDepth,
uint256 _intStateTreeDepth,
uint256 _voteOptionTreeDepth,
Mode _mode
DomainObjs.Mode _mode
) external view returns (SnarkCommon.VerifyingKey memory);

/// @notice Get the process verifying key
Expand All @@ -37,6 +32,6 @@ interface IVkRegistry {
uint256 _messageTreeDepth,
uint256 _voteOptionTreeDepth,
uint256 _messageBatchSize,
Mode _mode
DomainObjs.Mode _mode
) external view returns (SnarkCommon.VerifyingKey memory);
}
6 changes: 6 additions & 0 deletions contracts/contracts/utilities/DomainObjs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ contract DomainObjs {
/// @notice the length of a MACI message
uint8 public constant MESSAGE_DATA_LENGTH = 10;

/// @notice voting modes
enum Mode {
0xmad marked this conversation as resolved.
Show resolved Hide resolved
QV,
NON_QV
}

/// @title Message
/// @notice this struct represents a MACI message
/// @dev msgType: 1 for vote message, 2 for topup message (size 2)
Expand Down
Loading
Loading