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

chore(deps): bump @openzeppelin/contracts from 4.9.5 to 5.0.2 #981

Merged
merged 2 commits into from
Apr 18, 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 contracts/contracts/MACI.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { IPollFactory } from "./interfaces/IPollFactory.sol";
import { IMessageProcessorFactory } from "./interfaces/IMPFactory.sol";
Expand All @@ -17,268 +17,268 @@

/// @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, DomainObjs, Params, Utilities, Ownable {
contract MACI is IMACI, DomainObjs, Params, Utilities, Ownable(msg.sender) {
/// @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 _mode Voting mode
/// @return pollAddr a new Poll contract address
function deployPoll(
uint256 _duration,
TreeDepths memory _treeDepths,
PubKey memory _coordinatorPubKey,
address _verifier,
address _vkRegistry,
Mode _mode
) public virtual onlyOwner returns (PollContracts memory pollAddr) {
// cache the poll to a local variable so we can increment it
uint256 pollId = nextPollId;

// Increment the poll ID for the next poll
// 2 ** 256 polls available
unchecked {
nextPollId++;
}

if (pollId > 0) {
if (!stateAq.treeMerged()) revert PreviousPollNotCompleted(pollId);
}

MaxValues memory maxValues = MaxValues({
maxMessages: uint256(TREE_ARITY) ** _treeDepths.messageTreeDepth,
maxVoteOptions: uint256(TREE_ARITY) ** _treeDepths.voteOptionTreeDepth
});

address _owner = owner();

address p = pollFactory.deploy(
_duration,
maxValues,
_treeDepths,
_coordinatorPubKey,
address(this),
topupCredit,
_owner
);

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

polls[pollId] = p;

// store the addresses in a struct so they can be returned
pollAddr = PollContracts({ poll: p, messageProcessor: mp, tally: tally });

emit DeployPoll(pollId, _coordinatorPubKey.x, _coordinatorPubKey.y, pollAddr);
}

/// @inheritdoc IMACI
function mergeStateAqSubRoots(uint256 _numSrQueueOps, uint256 _pollId) public onlyPoll(_pollId) {
stateAq.mergeSubRoots(_numSrQueueOps);

// if we have merged all subtrees then put a block
if (stateAq.subTreesMerged()) {
subtreesMerged = true;
}
}

/// @inheritdoc IMACI
function mergeStateAq(uint256 _pollId) public onlyPoll(_pollId) returns (uint256 root) {
// remove block
subtreesMerged = false;

root = stateAq.merge(stateTreeDepth);
}

/// @inheritdoc IMACI
function getStateAqRoot() public view returns (uint256 root) {
root = stateAq.getMainRoot(stateTreeDepth);
}

/// @notice Get the Poll details
/// @param _pollId The identifier of the Poll to retrieve
/// @return poll The Poll contract object
function getPoll(uint256 _pollId) public view returns (address poll) {
if (_pollId >= nextPollId) revert PollDoesNotExist(_pollId);
poll = polls[_pollId];
}
}

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract MACI has payable functions:
- MACI.constructor(IPollFactory,IMessageProcessorFactory,ITallyFactory,SignUpGatekeeper,InitialVoiceCreditProxy,TopupCredit,uint8)
But does not have a function to withdraw the ether
4 changes: 2 additions & 2 deletions contracts/contracts/MessageProcessor.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { AccQueue } from "./trees/AccQueue.sol";
import { IMACI } from "./interfaces/IMACI.sol";
Expand All @@ -17,279 +17,279 @@
/// @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, DomainObjs {
contract MessageProcessor is Ownable(msg.sender), 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;
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 _mode Voting mode
constructor(address _verifier, address _vkRegistry, address _poll, Mode _mode) payable {
verifier = IVerifier(_verifier);
vkRegistry = IVkRegistry(_vkRegistry);
poll = IPoll(_poll);
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
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,DomainObjs.Mode)
But does not have a function to withdraw the ether
4 changes: 2 additions & 2 deletions contracts/contracts/Poll.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { Params } from "./utilities/Params.sol";
import { SnarkCommon } from "./crypto/SnarkCommon.sol";
Expand All @@ -15,272 +15,272 @@
/// which can be either votes, key change messages or topup messages.
/// @dev Do not deploy this directly. Use PollFactory.deploy() which performs some
/// checks on the Poll constructor arguments.
contract Poll is Params, Utilities, SnarkCommon, Ownable, EmptyBallotRoots, IPoll {
contract Poll is Params, Utilities, SnarkCommon, Ownable(msg.sender), EmptyBallotRoots, IPoll {
using SafeERC20 for ERC20;

/// @notice Whether the Poll has been initialized
bool internal isInit;

/// @notice The coordinator's public key
PubKey public coordinatorPubKey;

/// @notice Hash of the coordinator's public key
uint256 public immutable coordinatorPubKeyHash;

/// @notice the state root of the state merkle tree
uint256 public mergedStateRoot;

// The timestamp of the block at which the Poll was deployed
uint256 internal immutable deployTime;

// The duration of the polling period, in seconds
uint256 internal immutable duration;

/// @notice Whether the MACI contract's stateAq has been merged by this contract
bool public stateAqMerged;

/// @notice Get the commitment to the state leaves and the ballots. This is
/// hash3(stateRoot, ballotRoot, salt).
/// Its initial value should be
/// hash(maciStateRootSnapshot, emptyBallotRoot, 0)
/// Each successful invocation of processMessages() should use a different
/// salt to update this value, so that an external observer cannot tell in
/// the case that none of the messages are valid.
uint256 public currentSbCommitment;

/// @notice The number of messages that have been published
uint256 public numMessages;

/// @notice The number of signups that have been processed
/// before the Poll ended (stateAq merged)
uint256 public numSignups;

/// @notice Max values for the poll
MaxValues public maxValues;

/// @notice Depths of the merkle trees
TreeDepths public treeDepths;

/// @notice The contracts used by the Poll
ExtContracts public extContracts;

error VotingPeriodOver();
error VotingPeriodNotOver();
error PollAlreadyInit();
error TooManyMessages();
error MaciPubKeyLargerThanSnarkFieldSize();
error StateAqAlreadyMerged();
error StateAqSubtreesNeedMerge();
error InvalidBatchLength();

event PublishMessage(Message _message, PubKey _encPubKey);
event TopupMessage(Message _message);
event MergeMaciStateAqSubRoots(uint256 indexed _numSrQueueOps);
event MergeMaciStateAq(uint256 indexed _stateRoot, uint256 indexed _numSignups);
event MergeMessageAqSubRoots(uint256 indexed _numSrQueueOps);
event MergeMessageAq(uint256 indexed _messageRoot);

/// @notice Each MACI instance can have multiple Polls.
/// When a Poll is deployed, its voting period starts immediately.
/// @param _duration The duration of the voting period, in seconds
/// @param _maxValues The maximum number of messages and vote options
/// @param _treeDepths The depths of the merkle trees
/// @param _coordinatorPubKey The coordinator's public key
/// @param _extContracts The external contracts
constructor(
uint256 _duration,
MaxValues memory _maxValues,
TreeDepths memory _treeDepths,
PubKey memory _coordinatorPubKey,
ExtContracts memory _extContracts
) payable {
// check that the coordinator public key is valid
if (_coordinatorPubKey.x >= SNARK_SCALAR_FIELD || _coordinatorPubKey.y >= SNARK_SCALAR_FIELD) {
revert MaciPubKeyLargerThanSnarkFieldSize();
}

// store the pub key as object then calculate the hash
coordinatorPubKey = _coordinatorPubKey;
// we hash it ourselves to ensure we store the correct value
coordinatorPubKeyHash = hashLeftRight(_coordinatorPubKey.x, _coordinatorPubKey.y);
// store the external contracts to interact with
extContracts = _extContracts;
// store duration of the poll
duration = _duration;
// store max values
maxValues = _maxValues;
// store tree depth
treeDepths = _treeDepths;
// Record the current timestamp
deployTime = block.timestamp;
}

/// @notice A modifier that causes the function to revert if the voting period is
/// not over.
modifier isAfterVotingDeadline() {
uint256 secondsPassed = block.timestamp - deployTime;
if (secondsPassed <= duration) revert VotingPeriodNotOver();
_;
}

/// @notice A modifier that causes the function to revert if the voting period is
/// over
modifier isWithinVotingDeadline() {
uint256 secondsPassed = block.timestamp - deployTime;
if (secondsPassed >= duration) revert VotingPeriodOver();
_;
}

/// @notice The initialization function.
/// @dev Should be called immediately after Poll creation
/// and messageAq ownership transferred
function init() public {
if (isInit) revert PollAlreadyInit();
// set to true so it cannot be called again
isInit = true;

unchecked {
numMessages++;
}

// init messageAq here by inserting placeholderLeaf
uint256[2] memory dat;
dat[0] = NOTHING_UP_MY_SLEEVE;
dat[1] = 0;

(Message memory _message, PubKey memory _padKey, uint256 placeholderLeaf) = padAndHashMessage(dat, 1);
extContracts.messageAq.enqueue(placeholderLeaf);

emit PublishMessage(_message, _padKey);
}

/// @inheritdoc IPoll
function topup(uint256 stateIndex, uint256 amount) public virtual isWithinVotingDeadline {
// we check that we do not exceed the max number of messages
if (numMessages >= maxValues.maxMessages) revert TooManyMessages();

// cannot realistically overflow
unchecked {
numMessages++;
}

/// @notice topupCredit is a trusted token contract which reverts if the transfer fails
extContracts.topupCredit.transferFrom(msg.sender, address(this), amount);

uint256[2] memory dat;
dat[0] = stateIndex;
dat[1] = amount;

(Message memory _message, , uint256 messageLeaf) = padAndHashMessage(dat, 2);

extContracts.messageAq.enqueue(messageLeaf);

emit TopupMessage(_message);
}

/// @inheritdoc IPoll
function publishMessage(Message memory _message, PubKey calldata _encPubKey) public virtual isWithinVotingDeadline {
// we check that we do not exceed the max number of messages
if (numMessages >= maxValues.maxMessages) revert TooManyMessages();

// validate that the public key is valid
if (_encPubKey.x >= SNARK_SCALAR_FIELD || _encPubKey.y >= SNARK_SCALAR_FIELD) {
revert MaciPubKeyLargerThanSnarkFieldSize();
}

// cannot realistically overflow
unchecked {
numMessages++;
}

// we enforce that msgType here is 1 so we don't need checks
// at the circuit level
_message.msgType = 1;

uint256 messageLeaf = hashMessageAndEncPubKey(_message, _encPubKey);
extContracts.messageAq.enqueue(messageLeaf);

emit PublishMessage(_message, _encPubKey);
}

/// @notice submit a message batch
/// @dev Can only be submitted before the voting deadline
/// @param _messages the messages
/// @param _encPubKeys the encrypted public keys
function publishMessageBatch(Message[] calldata _messages, PubKey[] calldata _encPubKeys) external {
if (_messages.length != _encPubKeys.length) {
revert InvalidBatchLength();
}

uint256 len = _messages.length;
for (uint256 i = 0; i < len; ) {
// an event will be published by this function already
publishMessage(_messages[i], _encPubKeys[i]);

unchecked {
i++;
}
}
}

/// @inheritdoc IPoll
function mergeMaciStateAqSubRoots(uint256 _numSrQueueOps, uint256 _pollId) public onlyOwner isAfterVotingDeadline {
// This function cannot be called after the stateAq was merged
if (stateAqMerged) revert StateAqAlreadyMerged();

// merge subroots
extContracts.maci.mergeStateAqSubRoots(_numSrQueueOps, _pollId);

emit MergeMaciStateAqSubRoots(_numSrQueueOps);
}

/// @inheritdoc IPoll
function mergeMaciStateAq(uint256 _pollId) public onlyOwner isAfterVotingDeadline {
// This function can only be called once per Poll after the voting
// deadline
if (stateAqMerged) revert StateAqAlreadyMerged();

// set merged to true so it cannot be called again
stateAqMerged = true;

// the subtrees must have been merged first
if (!extContracts.maci.stateAq().subTreesMerged()) revert StateAqSubtreesNeedMerge();

mergedStateRoot = extContracts.maci.mergeStateAq(_pollId);

// Set currentSbCommitment
uint256[3] memory sb;
sb[0] = mergedStateRoot;
sb[1] = emptyBallotRoots[treeDepths.voteOptionTreeDepth - 1];
sb[2] = uint256(0);

currentSbCommitment = hash3(sb);

numSignups = extContracts.maci.numSignUps();
emit MergeMaciStateAq(mergedStateRoot, numSignups);
}

/// @inheritdoc IPoll
function mergeMessageAqSubRoots(uint256 _numSrQueueOps) public onlyOwner isAfterVotingDeadline {
extContracts.messageAq.mergeSubRoots(_numSrQueueOps);
emit MergeMessageAqSubRoots(_numSrQueueOps);
}

/// @inheritdoc IPoll
function mergeMessageAq() public onlyOwner isAfterVotingDeadline {
uint256 root = extContracts.messageAq.merge(treeDepths.messageTreeDepth);
emit MergeMessageAq(root);
}

/// @inheritdoc IPoll
function getDeployTimeAndDuration() public view returns (uint256 pollDeployTime, uint256 pollDuration) {
pollDeployTime = deployTime;
pollDuration = duration;
}

/// @inheritdoc IPoll
function numSignUpsAndMessages() public view returns (uint256 numSUps, uint256 numMsgs) {
numSUps = numSignups;
numMsgs = numMessages;
}
}

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract Poll has payable functions:
- Poll.constructor(uint256,Params.MaxValues,Params.TreeDepths,DomainObjs.PubKey,Params.ExtContracts)
But does not have a function to withdraw the ether
2 changes: 1 addition & 1 deletion contracts/contracts/PollFactory.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { IMACI } from "./interfaces/IMACI.sol";
import { AccQueue } from "./trees/AccQueue.sol";
Expand Down
4 changes: 2 additions & 2 deletions contracts/contracts/SignUpToken.sol
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

/// @title SignUpToken
/// @notice This contract is an ERC721 token contract which
/// can be used to allow users to sign up for a poll.
contract SignUpToken is ERC721, Ownable {
contract SignUpToken is ERC721, Ownable(msg.sender) {
/// @notice The constructor which calls the ERC721 constructor
constructor() payable ERC721("SignUpToken", "SignUpToken") {}

/// @notice Gives an ERC721 token to an address
/// @param to The address to give the token to
/// @param curTokenId The token id to give
function giveToken(address to, uint256 curTokenId) public onlyOwner {
_mint(to, curTokenId);
}
}

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

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

import { IMACI } from "./interfaces/IMACI.sol";
import { Hasher } from "./crypto/Hasher.sol";
Expand All @@ -15,362 +15,362 @@
/// @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, DomainObjs {
contract Tally is Ownable(msg.sender), 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;
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, Mode _mode) payable {
verifier = IVerifier(_verifier);
vkRegistry = IVkRegistry(_vkRegistry);
poll = IPoll(_poll);
messageProcessor = IMessageProcessor(_mp);
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
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;

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 (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 (mode == Mode.QV) {
uint256[3] memory tally;
tally[0] = hashLeftRight(computedRoot, _tallyResultSalt);
tally[1] = _spentVoiceCreditsHash;
tally[2] = _perVOSpentVoiceCreditsHash;

isValid = hash3(tally) == tallyCommitment;
} else if (mode == Mode.NON_QV) {
uint256[2] memory tally;
tally[0] = hashLeftRight(computedRoot, _tallyResultSalt);
tally[1] = _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,DomainObjs.Mode)
But does not have a function to withdraw the ether
4 changes: 2 additions & 2 deletions contracts/contracts/TopupCredit.sol
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

/// @title TopupCredit
/// @notice A contract representing a token used to topup a MACI's voter
/// credits
contract TopupCredit is ERC20, Ownable {
contract TopupCredit is ERC20, Ownable(msg.sender) {
uint8 public constant DECIMALS = 1;
uint256 public constant MAXIMUM_AIRDROP_AMOUNT = 100000 * 10 ** DECIMALS;

/// @notice custom errors
error ExceedLimit();

/// @notice create a new TopupCredit token
constructor() payable ERC20("TopupCredit", "TopupCredit") {}

/// @notice mint tokens to an account
/// @param account the account to mint tokens to
/// @param amount the amount of tokens to mint
function airdropTo(address account, uint256 amount) public onlyOwner {
if (amount >= MAXIMUM_AIRDROP_AMOUNT) {
revert ExceedLimit();
}

_mint(account, amount);
}

/// @notice mint tokens to the contract owner
/// @param amount the amount of tokens to mint
function airdrop(uint256 amount) public onlyOwner {
if (amount >= MAXIMUM_AIRDROP_AMOUNT) {
revert ExceedLimit();
}

_mint(msg.sender, amount);
}
}

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract TopupCredit has payable functions:
- TopupCredit.constructor()
But does not have a function to withdraw the ether

Check warning

Code scanning / Slither

Too many digits Warning

4 changes: 2 additions & 2 deletions contracts/contracts/VkRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { SnarkCommon } from "./crypto/SnarkCommon.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
Expand All @@ -10,257 +10,257 @@
/// @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, DomainObjs, SnarkCommon, IVkRegistry {
contract VkRegistry is Ownable(msg.sender), 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);

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;

uint256 processIcLength = _processVk.ic.length;
for (uint256 i = 0; i < processIcLength; ) {
processVk.ic.push(_processVk.ic[i]);

unchecked {
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;

uint256 tallyIcLength = _tallyVk.ic.length;
for (uint256 i = 0; i < tallyIcLength; ) {
tallyVk.ic.push(_tallyVk.ic[i]);

unchecked {
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
2 changes: 1 addition & 1 deletion contracts/contracts/benchmarks/HasherBenchmarks.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { Hasher } from "../crypto/Hasher.sol";

Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/crypto/Hasher.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { SnarkConstants } from "./SnarkConstants.sol";
import { PoseidonT3 } from "./PoseidonT3.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/crypto/MockVerifier.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { SnarkConstants } from "./SnarkConstants.sol";
import { SnarkCommon } from "./SnarkCommon.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/crypto/Pairing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

// 2019 OKIMS

pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

/// @title Pairing
/// @notice A library implementing the alt_bn128 elliptic curve operations.
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/crypto/PoseidonT3.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

/// @notice A library which provides functions for computing Pedersen hashes.
library PoseidonT3 {
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/crypto/PoseidonT4.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

/// @notice A library which provides functions for computing Pedersen hashes.
library PoseidonT4 {
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/crypto/PoseidonT5.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

/// @notice A library which provides functions for computing Pedersen hashes.
library PoseidonT5 {
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/crypto/PoseidonT6.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

/// @notice A library which provides functions for computing Pedersen hashes.
library PoseidonT6 {
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/crypto/SnarkCommon.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;
import { Pairing } from "./Pairing.sol";

/// @title SnarkCommon
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/crypto/SnarkConstants.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

/// @title SnarkConstants
/// @notice This contract contains constants related to the SNARK
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/crypto/Verifier.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { Pairing } from "./Pairing.sol";
import { SnarkConstants } from "./SnarkConstants.sol";
Expand Down
4 changes: 2 additions & 2 deletions contracts/contracts/gatekeepers/EASGatekeeper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,79 +9,79 @@
/// @title EASGatekeeper
/// @notice A gatekeeper contract which allows users to sign up to MACI
/// only if they've received an attestation of a specific schema from a trusted attester
contract EASGatekeeper is SignUpGatekeeper, Ownable {
contract EASGatekeeper is SignUpGatekeeper, Ownable(msg.sender) {
// the reference to the EAS contract
IEAS private immutable eas;

// the schema to check against
bytes32 public immutable schema;

// the trusted attester
address public immutable attester;

/// @notice the reference to the MACI contract
address public maci;

// a mapping of attestations that have already registered
mapping(bytes32 => bool) public registeredAttestations;

/// @notice custom errors
error AttestationRevoked();
error AlreadyRegistered();
error AttesterNotTrusted();
error NotYourAttestation();
error InvalidSchema();
error OnlyMACI();
error ZeroAddress();

/// @notice Deploy an instance of EASGatekeeper
/// @param _eas The EAS contract
/// @param _attester The trusted attester
/// @param _schema The schema UID
constructor(address _eas, address _attester, bytes32 _schema) payable Ownable() {
constructor(address _eas, address _attester, bytes32 _schema) payable {
if (_eas == address(0) || _attester == address(0)) revert ZeroAddress();
eas = IEAS(_eas);
schema = _schema;
attester = _attester;
}

/// @notice Adds an uninitialised MACI instance to allow for token signups
/// @param _maci The MACI contract interface to be stored
function setMaciInstance(address _maci) public override onlyOwner {
if (_maci == address(0)) revert ZeroAddress();
maci = _maci;
}

/// @notice Register an user based on their attestation
/// @dev Throw if the attestation is not valid or just complete silently
/// @param _user The user's Ethereum address.
/// @param _data The ABI-encoded schemaId as a uint256.
function register(address _user, bytes memory _data) public override {
// decode the argument
bytes32 attestationId = abi.decode(_data, (bytes32));

// ensure that the caller is the MACI contract
if (maci != msg.sender) revert OnlyMACI();

// ensure that the attestation has not been registered yet
if (registeredAttestations[attestationId]) revert AlreadyRegistered();

// register the attestation so it cannot be called again with the same one
registeredAttestations[attestationId] = true;

// get the attestation from the EAS contract
IEAS.Attestation memory attestation = eas.getAttestation(attestationId);

// the schema must match
if (attestation.schema != schema) revert InvalidSchema();

// we check that the attestation attester is the trusted one
if (attestation.attester != attester) revert AttesterNotTrusted();

// we check that it was not revoked
if (attestation.revocationTime != 0) revert AttestationRevoked();

// one cannot register an attestation for another user
if (attestation.recipient != _user) revert NotYourAttestation();
}
}

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract EASGatekeeper has payable functions:
- EASGatekeeper.constructor(address,address,bytes32)
But does not have a function to withdraw the ether
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { SignUpGatekeeper } from "./SignUpGatekeeper.sol";

Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/gatekeepers/HatsGatekeeperBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { SignUpGatekeeper } from "./SignUpGatekeeper.sol";

/// @title HatsGatekeeperBase
/// @notice Abstract contract containing the base elements of a Hats Gatekeeper contract
abstract contract HatsGatekeeperBase is SignUpGatekeeper, Ownable {
abstract contract HatsGatekeeperBase is SignUpGatekeeper, Ownable(msg.sender) {
/*//////////////////////////////////////////////////////////////
CUSTOM ERRORS
//////////////////////////////////////////////////////////////*/
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/gatekeepers/SignUpGatekeeper.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

/// @title SignUpGatekeeper
/// @notice A gatekeeper contract which allows users to sign up for a poll.
Expand Down
6 changes: 3 additions & 3 deletions contracts/contracts/gatekeepers/SignUpTokenGatekeeper.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

Expand All @@ -9,51 +9,51 @@
/// @title SignUpTokenGatekeeper
/// @notice This contract allows to gatekeep MACI signups
/// by requiring new voters to own a certain ERC721 token
contract SignUpTokenGatekeeper is SignUpGatekeeper, Ownable {
contract SignUpTokenGatekeeper is SignUpGatekeeper, Ownable(msg.sender) {
/// @notice the reference to the SignUpToken contract
SignUpToken public token;
/// @notice the reference to the MACI contract
address public maci;

/// @notice a mapping of tokenIds to whether they have been used to sign up
mapping(uint256 => bool) public registeredTokenIds;

/// @notice custom errors
error AlreadyRegistered();
error NotTokenOwner();
error OnlyMACI();

/// @notice creates a new SignUpTokenGatekeeper
/// @param _token the address of the SignUpToken contract
constructor(SignUpToken _token) payable Ownable() {
constructor(SignUpToken _token) payable {
token = _token;
}

/// @notice Adds an uninitialised MACI instance to allow for token signups
/// @param _maci The MACI contract interface to be stored
function setMaciInstance(address _maci) public override onlyOwner {
maci = _maci;
}

/// @notice Registers the user if they own the token with the token ID encoded in
/// _data. Throws if the user does not own the token or if the token has
/// already been used to sign up.
/// @param _user The user's Ethereum address.
/// @param _data The ABI-encoded tokenId as a uint256.
function register(address _user, bytes memory _data) public override {
if (maci != msg.sender) revert OnlyMACI();
// Decode the given _data bytes into a uint256 which is the token ID
uint256 tokenId = abi.decode(_data, (uint256));

// Check if the user owns the token
bool ownsToken = token.ownerOf(tokenId) == _user;
if (!ownsToken) revert NotTokenOwner();

// Check if the token has already been used
bool alreadyRegistered = registeredTokenIds[tokenId];
if (alreadyRegistered) revert AlreadyRegistered();

// Mark the token as already used
registeredTokenIds[tokenId] = true;
}
}

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract SignUpTokenGatekeeper has payable functions:
- SignUpTokenGatekeeper.constructor(SignUpToken)
But does not have a function to withdraw the ether
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { InitialVoiceCreditProxy } from "./InitialVoiceCreditProxy.sol";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

/// @title InitialVoiceCreditProxy
/// @notice This contract is the base contract for
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/interfaces/IMACI.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { AccQueue } from "../trees/AccQueue.sol";

Expand Down
4 changes: 2 additions & 2 deletions contracts/contracts/trees/AccQueue.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Hasher } from "../crypto/Hasher.sol";
Expand All @@ -10,7 +10,7 @@ import { Hasher } from "../crypto/Hasher.sol";
/// subtrees together. Merging subtrees requires at least 2 operations:
/// mergeSubRoots(), and merge(). To get around the gas limit,
/// the mergeSubRoots() can be performed in multiple transactions.
abstract contract AccQueue is Ownable, Hasher {
abstract contract AccQueue is Ownable(msg.sender), Hasher {
// The maximum tree depth
uint256 public constant MAX_DEPTH = 32;

Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/AccQueueBinary.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { AccQueue } from "./AccQueue.sol";

Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/AccQueueBinary0.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { MerkleZeros as MerkleBinary0 } from "./zeros/MerkleBinary0.sol";
import { AccQueueBinary } from "./AccQueueBinary.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/AccQueueBinaryMaci.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { MerkleZeros as MerkleBinaryMaci } from "./zeros/MerkleBinaryMaci.sol";
import { AccQueueBinary } from "./AccQueueBinary.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/AccQueueQuinary.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { AccQueue } from "./AccQueue.sol";

Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/AccQueueQuinary0.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { MerkleZeros as MerkleQuinary0 } from "./zeros/MerkleQuinary0.sol";
import { AccQueueQuinary } from "./AccQueueQuinary.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/AccQueueQuinaryBlankSl.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { MerkleZeros as MerkleQuinaryBlankSl } from "./zeros/MerkleQuinaryBlankSl.sol";
import { AccQueueQuinary } from "./AccQueueQuinary.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/AccQueueQuinaryMaci.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { MerkleZeros as MerkleQuinaryMaci } from "./zeros/MerkleQuinaryMaci.sol";
import { AccQueueQuinary } from "./AccQueueQuinary.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/EmptyBallotRoots.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

abstract contract EmptyBallotRoots {
// emptyBallotRoots contains the roots of Ballot trees of five leaf
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/zeros/MerkleBinary0.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

abstract contract MerkleZeros {
uint256[33] internal zeros;
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/zeros/MerkleBinaryMaci.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

abstract contract MerkleZeros {
uint256[33] internal zeros;
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/zeros/MerkleQuinary0.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

abstract contract MerkleZeros {
uint256[33] internal zeros;
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/zeros/MerkleQuinaryBlankSl.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

abstract contract MerkleZeros {
uint256[33] internal zeros;
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/trees/zeros/MerkleQuinaryMaci.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

abstract contract MerkleZeros {
uint256[33] internal zeros;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

abstract contract MerkleZeros {
uint256[33] internal zeros;
Expand Down
Loading
Loading