Source Code
Overview
ETH Balance
More Info
ContractCreator
Multichain Info
N/A
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Poll
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { Params } from "./utilities/Params.sol";
import { SnarkCommon } from "./crypto/SnarkCommon.sol";
import { IPoll } from "./interfaces/IPoll.sol";
import { Utilities } from "./utilities/Utilities.sol";
import { CurveBabyJubJub } from "./crypto/BabyJubJub.sol";
/// @title Poll
/// @notice A Poll contract allows voters to submit encrypted messages
/// which can be either votes or key change 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, IPoll {
/// @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 The root of the empty ballot tree at a given voteOptionTree depth
uint256 public immutable emptyBallotRoot;
/// @notice Whether the MACI contract's stateAq has been merged by this contract
bool public stateMerged;
/// @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 The actual depth of the state tree
/// to be used as public input for the circuit
uint8 public actualStateTreeDepth;
/// @notice Depths of the merkle trees
TreeDepths public treeDepths;
/// @notice The contracts used by the Poll
ExtContracts public extContracts;
/// @notice The max number of messages
uint256 public immutable maxMessages;
/// @notice The number of children per node in the merkle trees
uint256 internal constant TREE_ARITY = 5;
error VotingPeriodOver();
error VotingPeriodNotOver();
error PollAlreadyInit();
error TooManyMessages();
error InvalidPubKey();
error StateAlreadyMerged();
error InvalidBatchLength();
event PublishMessage(Message _message, PubKey _encPubKey);
event MergeMaciState(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 _treeDepths The depths of the merkle trees
/// @param _coordinatorPubKey The coordinator's public key
/// @param _extContracts The external contracts
constructor(
uint256 _duration,
TreeDepths memory _treeDepths,
PubKey memory _coordinatorPubKey,
ExtContracts memory _extContracts,
uint256 _emptyBallotRoot
) payable {
// check that the coordinator public key is valid
if (!CurveBabyJubJub.isOnCurve(_coordinatorPubKey.x, _coordinatorPubKey.y)) {
revert InvalidPubKey();
}
// 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 tree depth
treeDepths = _treeDepths;
// Record the current timestamp
deployTime = block.timestamp;
// store the empty ballot root
emptyBallotRoot = _emptyBallotRoot;
// store max messages
maxMessages = TREE_ARITY ** _treeDepths.messageTreeDepth;
}
/// @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);
extContracts.messageAq.enqueue(placeholderLeaf);
emit PublishMessage(_message, _padKey);
}
/// @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 >= maxMessages) revert TooManyMessages();
// check if the public key is on the curve
if (!CurveBabyJubJub.isOnCurve(_encPubKey.x, _encPubKey.y)) {
revert InvalidPubKey();
}
// cannot realistically overflow
unchecked {
numMessages++;
}
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 mergeMaciState() public isAfterVotingDeadline {
// This function can only be called once per Poll after the voting
// deadline
if (stateMerged) revert StateAlreadyMerged();
// set merged to true so it cannot be called again
stateMerged = true;
uint256 _mergedStateRoot = extContracts.maci.getStateTreeRoot();
mergedStateRoot = _mergedStateRoot;
// Set currentSbCommitment
uint256[3] memory sb;
sb[0] = _mergedStateRoot;
sb[1] = emptyBallotRoot;
sb[2] = uint256(0);
currentSbCommitment = hash3(sb);
// get number of signups and cache in a var for later use
uint256 _numSignups = extContracts.maci.numSignUps();
numSignups = _numSignups;
// dynamically determine the actual depth of the state tree
uint8 depth = 1;
while (uint40(1 << depth) < _numSignups) {
depth++;
}
actualStateTreeDepth = depth;
emit MergeMaciState(_mergedStateRoot, _numSignups);
}
/// @inheritdoc IPoll
function mergeMessageAqSubRoots(uint256 _numSrQueueOps) public isAfterVotingDeadline {
extContracts.messageAq.mergeSubRoots(_numSrQueueOps);
emit MergeMessageAqSubRoots(_numSrQueueOps);
}
/// @inheritdoc IPoll
function mergeMessageAq() public 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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// @note This code was taken from
// https://github.com/yondonfu/sol-baby-jubjub/blob/master/contracts/CurveBabyJubJub.sol
// Thanks to yondonfu for the code
// Implementation cited on baby-jubjub's paper
// https://eips.ethereum.org/EIPS/eip-2494#implementation
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
library CurveBabyJubJub {
// Curve parameters
// E: 168700x^2 + y^2 = 1 + 168696x^2y^2
// A = 168700
uint256 public constant A = 0x292FC;
// D = 168696
uint256 public constant D = 0x292F8;
// Prime Q = 21888242871839275222246405745257275088548364400416034343698204186575808495617
uint256 public constant Q = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001;
/**
* @dev Add 2 points on baby jubjub curve
* Formula for adding 2 points on a twisted Edwards curve:
* x3 = (x1y2 + y1x2) / (1 + dx1x2y1y2)
* y3 = (y1y2 - ax1x2) / (1 - dx1x2y1y2)
*/
function pointAdd(uint256 _x1, uint256 _y1, uint256 _x2, uint256 _y2) internal view returns (uint256 x3, uint256 y3) {
if (_x1 == 0 && _y1 == 0) {
return (_x2, _y2);
}
if (_x2 == 0 && _y1 == 0) {
return (_x1, _y1);
}
uint256 x1x2 = mulmod(_x1, _x2, Q);
uint256 y1y2 = mulmod(_y1, _y2, Q);
uint256 dx1x2y1y2 = mulmod(D, mulmod(x1x2, y1y2, Q), Q);
uint256 x3Num = addmod(mulmod(_x1, _y2, Q), mulmod(_y1, _x2, Q), Q);
uint256 y3Num = submod(y1y2, mulmod(A, x1x2, Q), Q);
x3 = mulmod(x3Num, inverse(addmod(1, dx1x2y1y2, Q)), Q);
y3 = mulmod(y3Num, inverse(submod(1, dx1x2y1y2, Q)), Q);
}
/**
* @dev Double a point on baby jubjub curve
* Doubling can be performed with the same formula as addition
*/
function pointDouble(uint256 _x1, uint256 _y1) internal view returns (uint256 x2, uint256 y2) {
return pointAdd(_x1, _y1, _x1, _y1);
}
/**
* @dev Multiply a point on baby jubjub curve by a scalar
* Use the double and add algorithm
*/
function pointMul(uint256 _x1, uint256 _y1, uint256 _d) internal view returns (uint256 x2, uint256 y2) {
uint256 remaining = _d;
uint256 px = _x1;
uint256 py = _y1;
uint256 ax = 0;
uint256 ay = 0;
while (remaining != 0) {
if ((remaining & 1) != 0) {
// Binary digit is 1 so add
(ax, ay) = pointAdd(ax, ay, px, py);
}
(px, py) = pointDouble(px, py);
remaining = remaining / 2;
}
x2 = ax;
y2 = ay;
}
/**
* @dev Check if a given point is on the curve
* (168700x^2 + y^2) - (1 + 168696x^2y^2) == 0
*/
function isOnCurve(uint256 _x, uint256 _y) internal pure returns (bool) {
uint256 xSq = mulmod(_x, _x, Q);
uint256 ySq = mulmod(_y, _y, Q);
uint256 lhs = addmod(mulmod(A, xSq, Q), ySq, Q);
uint256 rhs = addmod(1, mulmod(mulmod(D, xSq, Q), ySq, Q), Q);
return submod(lhs, rhs, Q) == 0;
}
/**
* @dev Perform modular subtraction
*/
function submod(uint256 _a, uint256 _b, uint256 _mod) internal pure returns (uint256) {
uint256 aNN = _a;
if (_a <= _b) {
aNN += _mod;
}
return addmod(aNN - _b, 0, _mod);
}
/**
* @dev Compute modular inverse of a number
*/
function inverse(uint256 _a) internal view returns (uint256) {
// We can use Euler's theorem instead of the extended Euclidean algorithm
// Since m = Q and Q is prime we have: a^-1 = a^(m - 2) (mod m)
return expmod(_a, Q - 2, Q);
}
/**
* @dev Helper function to call the bigModExp precompile
*/
function expmod(uint256 _b, uint256 _e, uint256 _m) internal view returns (uint256 o) {
assembly {
let memPtr := mload(0x40)
mstore(memPtr, 0x20) // Length of base _b
mstore(add(memPtr, 0x20), 0x20) // Length of exponent _e
mstore(add(memPtr, 0x40), 0x20) // Length of modulus _m
mstore(add(memPtr, 0x60), _b) // Base _b
mstore(add(memPtr, 0x80), _e) // Exponent _e
mstore(add(memPtr, 0xa0), _m) // Modulus _m
// The bigModExp precompile is at 0x05
let success := staticcall(gas(), 0x05, memPtr, 0xc0, memPtr, 0x20)
switch success
case 0 {
revert(0x0, 0x0)
}
default {
o := mload(memPtr)
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { SnarkConstants } from "./SnarkConstants.sol";
import { PoseidonT3 } from "./PoseidonT3.sol";
import { PoseidonT4 } from "./PoseidonT4.sol";
import { PoseidonT5 } from "./PoseidonT5.sol";
import { PoseidonT6 } from "./PoseidonT6.sol";
/// @notice A SHA256 hash function for any number of input elements, and Poseidon hash
/// functions for 2, 3, 4, 5, and 12 input elements.
contract Hasher is SnarkConstants {
/// @notice Computes the SHA256 hash of an array of uint256 elements.
/// @param array The array of uint256 elements.
/// @return result The SHA256 hash of the array.
function sha256Hash(uint256[] memory array) public pure returns (uint256 result) {
result = uint256(sha256(abi.encodePacked(array))) % SNARK_SCALAR_FIELD;
}
/// @notice Computes the Poseidon hash of two uint256 elements.
/// @param array An array of two uint256 elements.
/// @return result The Poseidon hash of the two elements.
function hash2(uint256[2] memory array) public pure returns (uint256 result) {
result = PoseidonT3.poseidon(array);
}
/// @notice Computes the Poseidon hash of three uint256 elements.
/// @param array An array of three uint256 elements.
/// @return result The Poseidon hash of the three elements.
function hash3(uint256[3] memory array) public pure returns (uint256 result) {
result = PoseidonT4.poseidon(array);
}
/// @notice Computes the Poseidon hash of four uint256 elements.
/// @param array An array of four uint256 elements.
/// @return result The Poseidon hash of the four elements.
function hash4(uint256[4] memory array) public pure returns (uint256 result) {
result = PoseidonT5.poseidon(array);
}
/// @notice Computes the Poseidon hash of five uint256 elements.
/// @param array An array of five uint256 elements.
/// @return result The Poseidon hash of the five elements.
function hash5(uint256[5] memory array) public pure returns (uint256 result) {
result = PoseidonT6.poseidon(array);
}
/// @notice Computes the Poseidon hash of two uint256 elements.
/// @param left the first element to hash.
/// @param right the second element to hash.
/// @return result The Poseidon hash of the two elements.
function hashLeftRight(uint256 left, uint256 right) public pure returns (uint256 result) {
uint256[2] memory input;
input[0] = left;
input[1] = right;
result = hash2(input);
}
}// SPDX-License-Identifier: MIT
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// 2019 OKIMS
pragma solidity ^0.8.20;
/// @title Pairing
/// @notice A library implementing the alt_bn128 elliptic curve operations.
library Pairing {
uint256 public constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
struct G1Point {
uint256 x;
uint256 y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] x;
uint256[2] y;
}
/// @notice custom errors
error PairingAddFailed();
error PairingMulFailed();
error PairingOpcodeFailed();
/// @notice The negation of p, i.e. p.plus(p.negate()) should be zero.
function negate(G1Point memory p) internal pure returns (G1Point memory) {
// The prime q in the base field F_q for G1
if (p.x == 0 && p.y == 0) {
return G1Point(0, 0);
} else {
return G1Point(p.x, PRIME_Q - (p.y % PRIME_Q));
}
}
/// @notice r Returns the sum of two points of G1.
function plus(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
uint256[4] memory input;
input[0] = p1.x;
input[1] = p1.y;
input[2] = p2.x;
input[3] = p2.y;
bool success;
// solhint-disable-next-line no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
// Use "invalid" to make gas estimation work
switch success
case 0 {
invalid()
}
}
if (!success) {
revert PairingAddFailed();
}
}
/// @notice r Return the product of a point on G1 and a scalar, i.e.
/// p == p.scalarMul(1) and p.plus(p) == p.scalarMul(2) for all
/// points p.
function scalarMul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
uint256[3] memory input;
input[0] = p.x;
input[1] = p.y;
input[2] = s;
bool success;
// solhint-disable-next-line no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
// Use "invalid" to make gas estimation work
switch success
case 0 {
invalid()
}
}
if (!success) {
revert PairingMulFailed();
}
}
/// @return isValid The result of computing the pairing check
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
/// For example,
/// pairing([P1(), P1().negate()], [P2(), P2()]) should return true.
function pairing(
G1Point memory a1,
G2Point memory a2,
G1Point memory b1,
G2Point memory b2,
G1Point memory c1,
G2Point memory c2,
G1Point memory d1,
G2Point memory d2
) internal view returns (bool isValid) {
G1Point[4] memory p1;
p1[0] = a1;
p1[1] = b1;
p1[2] = c1;
p1[3] = d1;
G2Point[4] memory p2;
p2[0] = a2;
p2[1] = b2;
p2[2] = c2;
p2[3] = d2;
uint256 inputSize = 24;
uint256[] memory input = new uint256[](inputSize);
for (uint8 i = 0; i < 4; ) {
uint8 j = i * 6;
input[j + 0] = p1[i].x;
input[j + 1] = p1[i].y;
input[j + 2] = p2[i].x[0];
input[j + 3] = p2[i].x[1];
input[j + 4] = p2[i].y[0];
input[j + 5] = p2[i].y[1];
unchecked {
i++;
}
}
uint256[1] memory out;
bool success;
// solhint-disable-next-line no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
// Use "invalid" to make gas estimation work
switch success
case 0 {
invalid()
}
}
if (!success) {
revert PairingOpcodeFailed();
}
isValid = out[0] != 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @notice A library which provides functions for computing Pedersen hashes.
library PoseidonT3 {
// solhint-disable-next-line no-empty-blocks
function poseidon(uint256[2] memory input) public pure returns (uint256) {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @notice A library which provides functions for computing Pedersen hashes.
library PoseidonT4 {
// solhint-disable-next-line no-empty-blocks
function poseidon(uint256[3] memory input) public pure returns (uint256) {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @notice A library which provides functions for computing Pedersen hashes.
library PoseidonT5 {
// solhint-disable-next-line no-empty-blocks
function poseidon(uint256[4] memory input) public pure returns (uint256) {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @notice A library which provides functions for computing Pedersen hashes.
library PoseidonT6 {
// solhint-disable-next-line no-empty-blocks
function poseidon(uint256[5] memory input) public pure returns (uint256) {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { Pairing } from "./Pairing.sol";
/// @title SnarkCommon
/// @notice a Contract which holds a struct
/// representing a Groth16 verifying key
contract SnarkCommon {
/// @notice a struct representing a Groth16 verifying key
struct VerifyingKey {
Pairing.G1Point alpha1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] ic;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title SnarkConstants
/// @notice This contract contains constants related to the SNARK
/// components of MACI.
contract SnarkConstants {
/// @notice The scalar field
uint256 internal constant SNARK_SCALAR_FIELD =
21888242871839275222246405745257275088548364400416034343698204186575808495617;
/// @notice The public key here is the first Pedersen base
/// point from iden3's circomlib implementation of the Pedersen hash.
/// Since it is generated using a hash-to-curve function, we are
/// confident that no-one knows the private key associated with this
/// public key. See:
/// https://github.com/iden3/circomlib/blob/d5ed1c3ce4ca137a6b3ca48bec4ac12c1b38957a/src/pedersen_printbases.js
/// Its hash should equal
/// 6769006970205099520508948723718471724660867171122235270773600567925038008762.
uint256 internal constant PAD_PUBKEY_X =
10457101036533406547632367118273992217979173478358440826365724437999023779287;
uint256 internal constant PAD_PUBKEY_Y =
19824078218392094440610104313265183977899662750282163392862422243483260492317;
/// @notice The Keccack256 hash of 'Maci'
uint256 internal constant NOTHING_UP_MY_SLEEVE =
8370432830353022751713833565135785980866757267633941821328460903436894336785;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title IMACI
/// @notice MACI interface
interface IMACI {
/// @notice Get the depth of the state tree
/// @return The depth of the state tree
function stateTreeDepth() external view returns (uint8);
/// @notice Return the main root of the StateAq contract
/// @return The Merkle root
function getStateTreeRoot() external view returns (uint256);
/// @notice Get the number of signups
/// @return numsignUps The number of signups
function numSignUps() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import { DomainObjs } from "../utilities/DomainObjs.sol";
import { IMACI } from "./IMACI.sol";
import { AccQueue } from "../trees/AccQueue.sol";
/// @title IPoll
/// @notice Poll interface
interface IPoll {
/// @notice The number of messages which have been processed and the number of signups
/// @return numSignups The number of signups
/// @return numMsgs The number of messages sent by voters
function numSignUpsAndMessages() external view returns (uint256 numSignups, uint256 numMsgs);
/// @notice Allows anyone to publish a message (an encrypted command and signature).
/// This function also enqueues the message.
/// @param _message The message to publish
/// @param _encPubKey An ephemeral public key which can be combined with the
/// coordinator's private key to generate an ECDH shared key with which
/// to encrypt the message.
function publishMessage(DomainObjs.Message memory _message, DomainObjs.PubKey calldata _encPubKey) external;
/// @notice The second step of merging the MACI state AccQueue. This allows the
/// ProcessMessages circuit to access the latest state tree and ballots via
/// currentSbCommitment.
function mergeMaciState() external;
/// @notice The first step in merging the message AccQueue so that the
/// ProcessMessages circuit can access the message root.
/// @param _numSrQueueOps The number of subroot queue operations to perform
function mergeMessageAqSubRoots(uint256 _numSrQueueOps) external;
/// @notice The second step in merging the message AccQueue so that the
/// ProcessMessages circuit can access the message root.
function mergeMessageAq() external;
/// @notice Returns the Poll's deploy time and duration
/// @return _deployTime The deployment timestamp
/// @return _duration The duration of the poll
function getDeployTimeAndDuration() external view returns (uint256 _deployTime, uint256 _duration);
/// @notice Get the result of whether the MACI contract's stateAq has been merged by this contract
/// @return Whether the MACI contract's stateAq has been merged by this contract
function stateMerged() external view returns (bool);
/// @notice Get the depths of the merkle trees
/// @return intStateTreeDepth The depth of the state tree
/// @return messageTreeSubDepth The subdepth of the message tree
/// @return messageTreeDepth The depth of the message tree
/// @return voteOptionTreeDepth The subdepth of the vote option tree
function treeDepths()
external
view
returns (uint8 intStateTreeDepth, uint8 messageTreeSubDepth, uint8 messageTreeDepth, uint8 voteOptionTreeDepth);
/// @notice Get the external contracts
/// @return maci The IMACI contract
/// @return messageAq The AccQueue contract
function extContracts() external view returns (IMACI maci, AccQueue messageAq);
/// @notice Get the hash of coordinator's public key
/// @return _coordinatorPubKeyHash the hash of coordinator's public key
function coordinatorPubKeyHash() external view returns (uint256 _coordinatorPubKeyHash);
/// @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.
/// @return The commitment to the state leaves and the ballots
function currentSbCommitment() external view returns (uint256);
/// @notice Get the dynamic depth of the state tree at the time of poll
/// finalization (based on the number of leaves inserted)
function actualStateTreeDepth() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Hasher } from "../crypto/Hasher.sol";
/// @title AccQueue
/// @notice This contract defines a Merkle tree where each leaf insertion only updates a
/// subtree. To obtain the main tree root, the contract owner must merge the
/// 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(msg.sender), Hasher {
// The maximum tree depth
uint256 public constant MAX_DEPTH = 32;
/// @notice A Queue is a 2D array of Merkle roots and indices which represents nodes
/// in a Merkle tree while it is progressively updated.
struct Queue {
/// @notice IMPORTANT: the following declares an array of b elements of type T: T[b]
/// And the following declares an array of b elements of type T[a]: T[a][b]
/// As such, the following declares an array of MAX_DEPTH+1 arrays of
/// uint256[4] arrays, **not the other way round**:
uint256[4][MAX_DEPTH + 1] levels;
uint256[MAX_DEPTH + 1] indices;
}
// The depth of each subtree
uint256 internal immutable subDepth;
// The number of elements per hash operation. Should be either 2 (for
// binary trees) or 5 (quinary trees). The limit is 5 because that is the
// maximum supported number of inputs for the EVM implementation of the
// Poseidon hash function
uint256 internal immutable hashLength;
// hashLength ** subDepth
uint256 internal immutable subTreeCapacity;
// True hashLength == 2, false if hashLength == 5
bool internal isBinary;
// The index of the current subtree. e.g. the first subtree has index 0, the
// second has 1, and so on
uint256 internal currentSubtreeIndex;
// Tracks the current subtree.
Queue internal leafQueue;
// Tracks the smallest tree of subroots
Queue internal subRootQueue;
// Subtree roots
mapping(uint256 => uint256) internal subRoots;
// Merged roots
uint256[MAX_DEPTH + 1] internal mainRoots;
// Whether the subtrees have been merged
bool public subTreesMerged;
// Whether entire merkle tree has been merged
bool public treeMerged;
// The root of the shortest possible tree which fits all current subtree
// roots
uint256 internal smallSRTroot;
// Tracks the next subroot to queue
uint256 internal nextSubRootIndex;
// The number of leaves inserted across all subtrees so far
uint256 public numLeaves;
/// @notice custom errors
error SubDepthCannotBeZero();
error SubdepthTooLarge(uint256 _subDepth, uint256 max);
error InvalidHashLength();
error DepthCannotBeZero();
error SubTreesAlreadyMerged();
error NothingToMerge();
error SubTreesNotMerged();
error DepthTooLarge(uint256 _depth, uint256 max);
error DepthTooSmall(uint256 _depth, uint256 min);
error InvalidIndex(uint256 _index);
error InvalidLevel();
/// @notice Create a new AccQueue
/// @param _subDepth The depth of each subtree.
/// @param _hashLength The number of leaves per node (2 or 5).
constructor(uint256 _subDepth, uint256 _hashLength) payable {
/// validation
if (_subDepth == 0) revert SubDepthCannotBeZero();
if (_subDepth > MAX_DEPTH) revert SubdepthTooLarge(_subDepth, MAX_DEPTH);
if (_hashLength != 2 && _hashLength != 5) revert InvalidHashLength();
isBinary = _hashLength == 2;
subDepth = _subDepth;
hashLength = _hashLength;
subTreeCapacity = _hashLength ** _subDepth;
}
/// @notice Hash the contents of the specified level and the specified leaf.
/// This is a virtual function as the hash function which the overriding
/// contract uses will be either hashLeftRight or hash5, which require
/// different input array lengths.
/// @param _level The level to hash.
/// @param _leaf The leaf include with the level.
/// @return _hash The hash of the level and leaf.
// solhint-disable-next-line no-empty-blocks
function hashLevel(uint256 _level, uint256 _leaf) internal virtual returns (uint256 _hash) {}
/// @notice Hash the contents of the specified level and the specified leaf.
/// This is a virtual function as the hash function which the overriding
/// contract uses will be either hashLeftRight or hash5, which require
/// different input array lengths.
/// @param _level The level to hash.
/// @param _leaf The leaf include with the level.
/// @return _hash The hash of the level and leaf.
// solhint-disable-next-line no-empty-blocks
function hashLevelLeaf(uint256 _level, uint256 _leaf) public view virtual returns (uint256 _hash) {}
/// @notice Returns the zero leaf at a specified level.
/// This is a virtual function as the hash function which the overriding
/// contract uses will be either hashLeftRight or hash5, which will produce
/// different zero values (e.g. hashLeftRight(0, 0) vs
/// hash5([0, 0, 0, 0, 0]). Moreover, the zero value may be a
/// nothing-up-my-sleeve value.
/// @param _level The level at which to return the zero leaf.
/// @return zero The zero leaf at the specified level.
// solhint-disable-next-line no-empty-blocks
function getZero(uint256 _level) internal virtual returns (uint256 zero) {}
/// @notice Add a leaf to the queue for the current subtree.
/// @param _leaf The leaf to add.
/// @return leafIndex The index of the leaf in the queue.
function enqueue(uint256 _leaf) public onlyOwner returns (uint256 leafIndex) {
leafIndex = numLeaves;
// Recursively queue the leaf
_enqueue(_leaf, 0);
// Update the leaf counter
numLeaves = leafIndex + 1;
// Now that a new leaf has been added, mainRoots and smallSRTroot are
// obsolete
delete mainRoots;
delete smallSRTroot;
subTreesMerged = false;
// If a subtree is full
if (numLeaves % subTreeCapacity == 0) {
// Store the subroot
subRoots[currentSubtreeIndex] = leafQueue.levels[subDepth][0];
// Increment the index
currentSubtreeIndex++;
// Delete ancillary data
delete leafQueue.levels[subDepth][0];
delete leafQueue.indices;
}
}
/// @notice Updates the queue at a given level and hashes any subroots
/// that need to be hashed.
/// @param _leaf The leaf to add.
/// @param _level The level at which to queue the leaf.
function _enqueue(uint256 _leaf, uint256 _level) internal {
if (_level > subDepth) {
revert InvalidLevel();
}
while (true) {
uint256 n = leafQueue.indices[_level];
if (n != hashLength - 1) {
// Just store the leaf
leafQueue.levels[_level][n] = _leaf;
if (_level != subDepth) {
// Update the index
leafQueue.indices[_level]++;
}
return;
}
// Hash the leaves to next level
_leaf = hashLevel(_level, _leaf);
// Reset the index for this level
delete leafQueue.indices[_level];
// Queue the hash of the leaves into to the next level
_level++;
}
}
/// @notice Fill any empty leaves of the current subtree with zeros and store the
/// resulting subroot.
function fill() public onlyOwner {
if (numLeaves % subTreeCapacity == 0) {
// If the subtree is completely empty, then the subroot is a
// precalculated zero value
subRoots[currentSubtreeIndex] = getZero(subDepth);
} else {
// Otherwise, fill the rest of the subtree with zeros
_fill(0);
// Store the subroot
subRoots[currentSubtreeIndex] = leafQueue.levels[subDepth][0];
// Reset the subtree data
delete leafQueue.levels;
// Reset the merged roots
delete mainRoots;
}
// Increment the subtree index
uint256 curr = currentSubtreeIndex + 1;
currentSubtreeIndex = curr;
// Update the number of leaves
numLeaves = curr * subTreeCapacity;
// Reset the subroot tree root now that it is obsolete
delete smallSRTroot;
subTreesMerged = false;
}
/// @notice A function that queues zeros to the specified level, hashes,
/// the level, and enqueues the hash to the next level.
/// @param _level The level at which to queue zeros.
// solhint-disable-next-line no-empty-blocks
function _fill(uint256 _level) internal virtual {}
/// Insert a subtree. Used for batch enqueues.
function insertSubTree(uint256 _subRoot) public onlyOwner {
subRoots[currentSubtreeIndex] = _subRoot;
// Increment the subtree index
currentSubtreeIndex++;
// Update the number of leaves
numLeaves += subTreeCapacity;
// Reset the subroot tree root now that it is obsolete
delete smallSRTroot;
subTreesMerged = false;
}
/// @notice Calculate the lowest possible height of a tree with
/// all the subroots merged together.
/// @return depth The lowest possible height of a tree with all the
function calcMinHeight() public view returns (uint256 depth) {
depth = 1;
while (true) {
if (hashLength ** depth >= currentSubtreeIndex) {
break;
}
depth++;
}
}
/// @notice Merge all subtrees to form the shortest possible tree.
/// This function can be called either once to merge all subtrees in a
/// single transaction, or multiple times to do the same in multiple
/// transactions.
/// @param _numSrQueueOps The number of times this function will call
/// queueSubRoot(), up to the maximum number of times
/// necessary. If it is set to 0, it will call
/// queueSubRoot() as many times as is necessary. Set
/// this to a low number and call this function
/// multiple times if there are many subroots to
/// merge, or a single transaction could run out of
/// gas.
function mergeSubRoots(uint256 _numSrQueueOps) public onlyOwner {
// This function can only be called once unless a new subtree is created
if (subTreesMerged) revert SubTreesAlreadyMerged();
// There must be subtrees to merge
if (numLeaves == 0) revert NothingToMerge();
// Fill any empty leaves in the current subtree with zeros only if the
// current subtree is not full
if (numLeaves % subTreeCapacity != 0) {
fill();
}
// If there is only 1 subtree, use its root
if (currentSubtreeIndex == 1) {
smallSRTroot = getSubRoot(0);
subTreesMerged = true;
return;
}
uint256 depth = calcMinHeight();
uint256 queueOpsPerformed = 0;
for (uint256 i = nextSubRootIndex; i < currentSubtreeIndex; i++) {
if (_numSrQueueOps != 0 && queueOpsPerformed == _numSrQueueOps) {
// If the limit is not 0, stop if the limit has been reached
return;
}
// Queue the next subroot
queueSubRoot(getSubRoot(nextSubRootIndex), 0, depth);
// Increment the next subroot counter
nextSubRootIndex++;
// Increment the ops counter
queueOpsPerformed++;
}
// The height of the tree of subroots
uint256 m = hashLength ** depth;
// Queue zeroes to fill out the SRT
if (nextSubRootIndex == currentSubtreeIndex) {
uint256 z = getZero(subDepth);
for (uint256 i = currentSubtreeIndex; i < m; i++) {
queueSubRoot(z, 0, depth);
}
}
// Store the smallest main root
smallSRTroot = subRootQueue.levels[depth][0];
subTreesMerged = true;
}
/// @notice Queues a subroot into the subroot tree.
/// @param _leaf The value to queue.
/// @param _level The level at which to queue _leaf.
/// @param _maxDepth The depth of the tree.
function queueSubRoot(uint256 _leaf, uint256 _level, uint256 _maxDepth) internal {
if (_level > _maxDepth) {
return;
}
uint256 n = subRootQueue.indices[_level];
if (n != hashLength - 1) {
// Just store the leaf
subRootQueue.levels[_level][n] = _leaf;
subRootQueue.indices[_level]++;
} else {
// Hash the elements in this level and queue it in the next level
uint256 hashed;
if (isBinary) {
uint256[2] memory inputs;
inputs[0] = subRootQueue.levels[_level][0];
inputs[1] = _leaf;
hashed = hash2(inputs);
} else {
uint256[5] memory inputs;
for (uint8 i = 0; i < n; i++) {
inputs[i] = subRootQueue.levels[_level][i];
}
inputs[n] = _leaf;
hashed = hash5(inputs);
}
// TODO: change recursion to a while loop
// Recurse
delete subRootQueue.indices[_level];
queueSubRoot(hashed, _level + 1, _maxDepth);
}
}
/// @notice Merge all subtrees to form a main tree with a desired depth.
/// @param _depth The depth of the main tree. It must fit all the leaves or
/// this function will revert.
/// @return root The root of the main tree.
function merge(uint256 _depth) public onlyOwner returns (uint256 root) {
// The tree depth must be more than 0
if (_depth == 0) revert DepthCannotBeZero();
// Ensure that the subtrees have been merged
if (!subTreesMerged) revert SubTreesNotMerged();
// Check the depth
if (_depth > MAX_DEPTH) revert DepthTooLarge(_depth, MAX_DEPTH);
// Calculate the SRT depth
uint256 srtDepth = subDepth;
while (true) {
if (hashLength ** srtDepth >= numLeaves) {
break;
}
srtDepth++;
}
if (_depth < srtDepth) revert DepthTooSmall(_depth, srtDepth);
// If the depth is the same as the SRT depth, just use the SRT root
if (_depth == srtDepth) {
mainRoots[_depth] = smallSRTroot;
treeMerged = true;
return smallSRTroot;
} else {
root = smallSRTroot;
// Calculate the main root
for (uint256 i = srtDepth; i < _depth; i++) {
uint256 z = getZero(i);
if (isBinary) {
uint256[2] memory inputs;
inputs[0] = root;
inputs[1] = z;
root = hash2(inputs);
} else {
uint256[5] memory inputs;
inputs[0] = root;
inputs[1] = z;
inputs[2] = z;
inputs[3] = z;
inputs[4] = z;
root = hash5(inputs);
}
}
mainRoots[_depth] = root;
treeMerged = true;
}
}
/// @notice Returns the subroot at the specified index. Reverts if the index refers
/// to a subtree which has not been filled yet.
/// @param _index The subroot index.
/// @return subRoot The subroot at the specified index.
function getSubRoot(uint256 _index) public view returns (uint256 subRoot) {
if (currentSubtreeIndex <= _index) revert InvalidIndex(_index);
subRoot = subRoots[_index];
}
/// @notice Returns the subroot tree (SRT) root. Its value must first be computed
/// using mergeSubRoots.
/// @return smallSubTreeRoot The SRT root.
function getSmallSRTroot() public view returns (uint256 smallSubTreeRoot) {
if (!subTreesMerged) revert SubTreesNotMerged();
smallSubTreeRoot = smallSRTroot;
}
/// @notice Return the merged Merkle root of all the leaves at a desired depth.
/// @dev merge() or merged(_depth) must be called first.
/// @param _depth The depth of the main tree. It must first be computed
/// using mergeSubRoots() and merge().
/// @return mainRoot The root of the main tree.
function getMainRoot(uint256 _depth) public view returns (uint256 mainRoot) {
if (hashLength ** _depth < numLeaves) revert DepthTooSmall(_depth, numLeaves);
mainRoot = mainRoots[_depth];
}
/// @notice Get the next subroot index and the current subtree index.
function getSrIndices() public view returns (uint256 next, uint256 current) {
next = nextSubRootIndex;
current = currentSubtreeIndex;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title DomainObjs
/// @notice An utility contract that holds
/// a number of domain objects and functions
contract DomainObjs {
/// @notice the length of a MACI message
uint8 public constant MESSAGE_DATA_LENGTH = 10;
/// @notice voting modes
enum Mode {
QV,
NON_QV
}
/// @title Message
/// @notice this struct represents a MACI message
/// @dev msgType: 1 for vote message
struct Message {
uint256[MESSAGE_DATA_LENGTH] data;
}
/// @title PubKey
/// @notice A MACI public key
struct PubKey {
uint256 x;
uint256 y;
}
/// @title StateLeaf
/// @notice A MACI state leaf
/// @dev used to represent a user's state
/// in the state Merkle tree
struct StateLeaf {
PubKey pubKey;
uint256 voiceCreditBalance;
uint256 timestamp;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { IMACI } from "../interfaces/IMACI.sol";
import { AccQueue } from "../trees/AccQueue.sol";
/// @title Params
/// @notice This contracts contains a number of structures
/// which are to be passed as parameters to Poll contracts.
/// This way we can reduce the number of parameters
/// and avoid a stack too deep error during compilation.
contract Params {
/// @notice A struct holding the depths of the merkle trees
struct TreeDepths {
uint8 intStateTreeDepth;
uint8 messageTreeSubDepth;
uint8 messageTreeDepth;
uint8 voteOptionTreeDepth;
}
/// @notice A struct holding the external contracts
/// that are to be passed to a Poll contract on
/// deployment
struct ExtContracts {
IMACI maci;
AccQueue messageAq;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { DomainObjs } from "./DomainObjs.sol";
import { Hasher } from "../crypto/Hasher.sol";
import { SnarkConstants } from "../crypto/SnarkConstants.sol";
/// @title Utilities
/// @notice An utility contract that can be used to:
/// * hash a state leaf
/// * pad and hash a MACI message
/// * hash a MACI message and an encryption public key
contract Utilities is SnarkConstants, DomainObjs, Hasher {
/// @notice custom errors
error InvalidMessage();
/// @notice An utility function used to hash a state leaf
/// @param _stateLeaf the state leaf to be hashed
/// @return ciphertext The hash of the state leaf
function hashStateLeaf(StateLeaf memory _stateLeaf) public pure returns (uint256 ciphertext) {
uint256[4] memory plaintext;
plaintext[0] = _stateLeaf.pubKey.x;
plaintext[1] = _stateLeaf.pubKey.y;
plaintext[2] = _stateLeaf.voiceCreditBalance;
plaintext[3] = _stateLeaf.timestamp;
ciphertext = hash4(plaintext);
}
/// @notice An utility function used to pad and hash a MACI message
/// @param dataToPad the data to be padded
/// @return message The padded message
/// @return padKey The padding public key
/// @return msgHash The hash of the padded message and encryption key
function padAndHashMessage(
uint256[2] memory dataToPad
) public pure returns (Message memory message, PubKey memory padKey, uint256 msgHash) {
// add data and pad it to 10 elements (automatically cause it's the default value)
uint256[10] memory dat;
dat[0] = dataToPad[0];
dat[1] = dataToPad[1];
padKey = PubKey(PAD_PUBKEY_X, PAD_PUBKEY_Y);
message = Message({ data: dat });
msgHash = hashMessageAndEncPubKey(message, padKey);
}
/// @notice An utility function used to hash a MACI message and an encryption public key
/// @param _message the message to be hashed
/// @param _encPubKey the encryption public key to be hashed
/// @return msgHash The hash of the message and the encryption public key
function hashMessageAndEncPubKey(
Message memory _message,
PubKey memory _encPubKey
) public pure returns (uint256 msgHash) {
if (_message.data.length != 10) {
revert InvalidMessage();
}
uint256[5] memory n;
n[0] = _message.data[0];
n[1] = _message.data[1];
n[2] = _message.data[2];
n[3] = _message.data[3];
n[4] = _message.data[4];
uint256[5] memory m;
m[0] = _message.data[5];
m[1] = _message.data[6];
m[2] = _message.data[7];
m[3] = _message.data[8];
m[4] = _message.data[9];
msgHash = hash4([hash5(n), hash5(m), _encPubKey.x, _encPubKey.y]);
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/crypto/PoseidonT3.sol": {
"PoseidonT3": "0x88c2c6a7535463962a34757fe63cc4f296381aba"
},
"contracts/crypto/PoseidonT4.sol": {
"PoseidonT4": "0xf8e637e5c9ec3a8d8fa8843a6df833348e1f1e66"
},
"contracts/crypto/PoseidonT5.sol": {
"PoseidonT5": "0x0a0d66bafda8c8838281084d9c3d68dd9a6fc274"
},
"contracts/crypto/PoseidonT6.sol": {
"PoseidonT6": "0xd2f6c828606ad8e985008cd825012f269b50cd58"
}
}
}Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"},{"components":[{"internalType":"uint8","name":"intStateTreeDepth","type":"uint8"},{"internalType":"uint8","name":"messageTreeSubDepth","type":"uint8"},{"internalType":"uint8","name":"messageTreeDepth","type":"uint8"},{"internalType":"uint8","name":"voteOptionTreeDepth","type":"uint8"}],"internalType":"struct Params.TreeDepths","name":"_treeDepths","type":"tuple"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct DomainObjs.PubKey","name":"_coordinatorPubKey","type":"tuple"},{"components":[{"internalType":"contract IMACI","name":"maci","type":"address"},{"internalType":"contract AccQueue","name":"messageAq","type":"address"}],"internalType":"struct Params.ExtContracts","name":"_extContracts","type":"tuple"},{"internalType":"uint256","name":"_emptyBallotRoot","type":"uint256"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"InvalidBatchLength","type":"error"},{"inputs":[],"name":"InvalidMessage","type":"error"},{"inputs":[],"name":"InvalidPubKey","type":"error"},{"inputs":[],"name":"PollAlreadyInit","type":"error"},{"inputs":[],"name":"StateAlreadyMerged","type":"error"},{"inputs":[],"name":"TooManyMessages","type":"error"},{"inputs":[],"name":"VotingPeriodNotOver","type":"error"},{"inputs":[],"name":"VotingPeriodOver","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_stateRoot","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_numSignups","type":"uint256"}],"name":"MergeMaciState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_messageRoot","type":"uint256"}],"name":"MergeMessageAq","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_numSrQueueOps","type":"uint256"}],"name":"MergeMessageAqSubRoots","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256[10]","name":"data","type":"uint256[10]"}],"indexed":false,"internalType":"struct DomainObjs.Message","name":"_message","type":"tuple"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"indexed":false,"internalType":"struct DomainObjs.PubKey","name":"_encPubKey","type":"tuple"}],"name":"PublishMessage","type":"event"},{"inputs":[],"name":"MESSAGE_DATA_LENGTH","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"actualStateTreeDepth","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"coordinatorPubKey","outputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"coordinatorPubKeyHash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentSbCommitment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emptyBallotRoot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"extContracts","outputs":[{"internalType":"contract IMACI","name":"maci","type":"address"},{"internalType":"contract AccQueue","name":"messageAq","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDeployTimeAndDuration","outputs":[{"internalType":"uint256","name":"pollDeployTime","type":"uint256"},{"internalType":"uint256","name":"pollDuration","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[2]","name":"array","type":"uint256[2]"}],"name":"hash2","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[3]","name":"array","type":"uint256[3]"}],"name":"hash3","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[4]","name":"array","type":"uint256[4]"}],"name":"hash4","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[5]","name":"array","type":"uint256[5]"}],"name":"hash5","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"left","type":"uint256"},{"internalType":"uint256","name":"right","type":"uint256"}],"name":"hashLeftRight","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256[10]","name":"data","type":"uint256[10]"}],"internalType":"struct DomainObjs.Message","name":"_message","type":"tuple"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct DomainObjs.PubKey","name":"_encPubKey","type":"tuple"}],"name":"hashMessageAndEncPubKey","outputs":[{"internalType":"uint256","name":"msgHash","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct DomainObjs.PubKey","name":"pubKey","type":"tuple"},{"internalType":"uint256","name":"voiceCreditBalance","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct DomainObjs.StateLeaf","name":"_stateLeaf","type":"tuple"}],"name":"hashStateLeaf","outputs":[{"internalType":"uint256","name":"ciphertext","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxMessages","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mergeMaciState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mergeMessageAq","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numSrQueueOps","type":"uint256"}],"name":"mergeMessageAqSubRoots","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mergedStateRoot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numMessages","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numSignUpsAndMessages","outputs":[{"internalType":"uint256","name":"numSUps","type":"uint256"},{"internalType":"uint256","name":"numMsgs","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numSignups","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[2]","name":"dataToPad","type":"uint256[2]"}],"name":"padAndHashMessage","outputs":[{"components":[{"internalType":"uint256[10]","name":"data","type":"uint256[10]"}],"internalType":"struct DomainObjs.Message","name":"message","type":"tuple"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct DomainObjs.PubKey","name":"padKey","type":"tuple"},{"internalType":"uint256","name":"msgHash","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256[10]","name":"data","type":"uint256[10]"}],"internalType":"struct DomainObjs.Message","name":"_message","type":"tuple"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct DomainObjs.PubKey","name":"_encPubKey","type":"tuple"}],"name":"publishMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256[10]","name":"data","type":"uint256[10]"}],"internalType":"struct DomainObjs.Message[]","name":"_messages","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct DomainObjs.PubKey[]","name":"_encPubKeys","type":"tuple[]"}],"name":"publishMessageBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"array","type":"uint256[]"}],"name":"sha256Hash","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"stateMerged","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treeDepths","outputs":[{"internalType":"uint8","name":"intStateTreeDepth","type":"uint8"},{"internalType":"uint8","name":"messageTreeSubDepth","type":"uint8"},{"internalType":"uint8","name":"messageTreeDepth","type":"uint8"},{"internalType":"uint8","name":"voteOptionTreeDepth","type":"uint8"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6101206040526040516200212c3803806200212c8339810160408190526200002791620003da565b825160208401516200003a91906200013a565b62000058576040516379fae7af60e01b815260040160405180910390fd5b8251600181905560208401516002819055620000759190620001ef565b6080528151600a80546001600160a01b039283166001600160a01b031991821617909155602080850151600b80549190941692169190911790915560c08690528451600980549287015160408801805160608a015160ff90811663010000000263ff0000001992821662010000029290921663ffff0000199482166101000261ffff199098169190961617959095179190911692909217929092179091554260a05260e0829052516200012a906005620005c8565b61010052506200066f9350505050565b6000806000805160206200210c833981519152848509905060006000805160206200210c833981519152848509905060006000805160206200210c833981519152826000805160206200210c83398151915285620292fc0908905060006000805160206200210c83398151915280846000805160206200210c83398151915287620292f809096001089050620001e182826000805160206200210c83398151915262000218565b159450505050505b92915050565b6000620001fb620002db565b8381526020810183905262000210816200025b565b949350505050565b60008383811162000232576200022f8382620005f6565b90505b8280620002435762000243620005e0565b60006200025186846200060c565b0895945050505050565b6040516314d2f97b60e11b81526000907388c2c6a7535463962a34757fe63cc4f296381aba906329a5f2f6906200029790859060040162000622565b602060405180830381865af4158015620002b5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001e9919062000655565b60405180604001604052806002906020820280368337509192915050565b604080519081016001600160401b03811182821017156200032a57634e487b7160e01b600052604160045260246000fd5b60405290565b604051608081016001600160401b03811182821017156200032a57634e487b7160e01b600052604160045260246000fd5b805160ff811681146200037357600080fd5b919050565b6001600160a01b03811681146200038e57600080fd5b50565b600060408284031215620003a457600080fd5b620003ae620002f9565b90508151620003bd8162000378565b81526020820151620003cf8162000378565b602082015292915050565b6000806000806000858703610140811215620003f557600080fd5b865195506080601f19820112156200040c57600080fd5b6200041662000330565b620004246020890162000361565b8152620004346040890162000361565b6020820152620004476060890162000361565b60408201526200045a6080890162000361565b606082015294506040609f19820112156200047457600080fd5b506200047f620002f9565b60a0870151815260c087015160208201529250620004a18760e0880162000391565b915061012086015190509295509295909350565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156200050c578160001904821115620004f057620004f0620004b5565b80851615620004fe57918102915b93841c9390800290620004d0565b509250929050565b6000826200052557506001620001e9565b816200053457506000620001e9565b81600181146200054d5760028114620005585762000578565b6001915050620001e9565b60ff8411156200056c576200056c620004b5565b50506001821b620001e9565b5060208310610133831016604e8410600b84101617156200059d575081810a620001e9565b620005a98383620004cb565b8060001904821115620005c057620005c0620004b5565b029392505050565b6000620005d960ff84168362000514565b9392505050565b634e487b7160e01b600052601260045260246000fd5b80820180821115620001e957620001e9620004b5565b81810381811115620001e957620001e9620004b5565b60408101818360005b60028110156200064c5781518352602092830192909101906001016200062b565b50505092915050565b6000602082840312156200066857600080fd5b5051919050565b60805160a05160c05160e05161010051611a12620006fa60003960008181610299015261066b01526000818161033a0152610cf6015260008181610270015281816105100152818161062b01528181610ad00152610c0501526000818161024f015281816104e70152818161060201528181610aa70152610bdc015260006103940152611a126000f3fe608060405234801561001057600080fd5b50600436106101d95760003560e01c80637028bb0e11610104578063ac98e5df116100a2578063e1c7392a11610071578063e1c7392a14610490578063e33b13a014610498578063edbfe83f146104b5578063fba630f2146104d757600080fd5b8063ac98e5df146103e4578063bc14ee2b1461043a578063bea140b314610474578063c17268d91461048757600080fd5b80638aa0ba92116100de5780638aa0ba921461038f5780639c971729146103b65780639cfced97146103c9578063a28bc38c146103dc57600080fd5b80637028bb0e1461035c5780637d0a81c8146103695780638a2a3dfb1461037c57600080fd5b80634f367f0f1161017c578063623f54ac1161014b578063623f54ac146102f557806362a361bb14610308578063683f3dc31461031b5780636d582d341461033557600080fd5b80634f367f0f146102bb57806358bfc379146102c65780635bb93995146102d95780635d5909dd146102ec57600080fd5b806331e766a5116101b857806331e766a5146102175780633dfb88b21461023a5780634909229f1461024d5780634966efd61461029457600080fd5b8062329f2f146101de5780630f4cf692146101e857806327bea0da14610204575b600080fd5b6101e66104e0565b005b6101f160065481565b6040519081526020015b60405180910390f35b6101e66102123660046112aa565b6105fb565b600154600254610225919082565b604080519283526020830191909152016101fb565b6101f16102483660046112ed565b6107a5565b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000610225565b6101f17f000000000000000000000000000000000000000000000000000000000000000081565b600754600654610225565b6101f16102d436600461136b565b610826565b6101f16102e7366004611411565b6108ae565b6101f160075481565b6101e6610303366004611433565b6108d3565b6101f16103163660046114fc565b610958565b610323600a81565b60405160ff90911681526020016101fb565b6101f17f000000000000000000000000000000000000000000000000000000000000000081565b6008546103239060ff1681565b6101f16103773660046115a6565b610992565b6101f161038a366004611608565b6109d2565b6101f17f000000000000000000000000000000000000000000000000000000000000000081565b6101e66103c436600461163f565b610aa0565b6101f16103d7366004611658565b610b9b565b6101e6610bd5565b60095461040d9060ff808216916101008104821691620100008204811691630100000090041684565b6040805160ff958616815293851660208501529184169183019190915290911660608201526080016101fb565b600a54600b54610454916001600160a01b03908116911682565b604080516001600160a01b039384168152929091166020830152016101fb565b6101f16104823660046116b1565b610e10565b6101f160055481565b6101e6610e4a565b6004546104a59060ff1681565b60405190151581526020016101fb565b6104c86104c33660046114fc565b610f6d565b6040516101fb93929190611736565b6101f160035481565b600061050c7f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f0000000000000000000000000000000000000000000000000000000000000000811161054e57604051630931513d60e11b815260040160405180910390fd5b600b546009546040516324a47aeb60e01b81526201000090910460ff1660048201526000916001600160a01b0316906324a47aeb906024016020604051808303816000875af11580156105a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c9919061178c565b60405190915081907fc5624680ab5d50c84507f9e0dc2032163de2bda906ab8a661a53dd4d43bd5dc790600090a25050565b60006106277f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f000000000000000000000000000000000000000000000000000000000000000081106106695760405163148fb9a960e31b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000600654106106ab57604051631ec0b2f760e01b815260040160405180910390fd5b6106ba82356020840135611015565b6106d7576040516379fae7af60e01b815260040160405180910390fd5b60068054600101905560006106f58461038a368690038601866117a5565b600b54604051631ffc735d60e01b8152600481018390529192506001600160a01b031690631ffc735d906024016020604051808303816000875af1158015610741573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610765919061178c565b507f4be9ef9ae736055964ead1cf3c83a19c8b662b5df2bd4414776bb64d81f75d1584846040516107979291906117c1565b60405180910390a150505050565b60405163248f667760e01b8152600090730a0d66bafda8c8838281084d9c3d68dd9a6fc2749063248f6677906107df9085906004016117ea565b602060405180830381865af41580156107fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610820919061178c565b92915050565b60006000805160206119bd83398151915260028360405160200161084a919061181b565b60408051601f198184030181529082905261086491611851565b602060405180830381855afa158015610881573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906108a4919061178c565b6108209190611896565b60006108b86110fa565b838152602081018390526108cb81610958565b949350505050565b8281146108f35760405163ca3487f760e01b815260040160405180910390fd5b8260005b8181101561095057610948868683818110610914576109146118b8565b9050610140020180360381019061092b91906118ce565b85858481811061093d5761093d6118b8565b9050604002016105fb565b6001016108f7565b505050505050565b6040516314d2f97b60e11b81526000907388c2c6a7535463962a34757fe63cc4f296381aba906329a5f2f6906107df9085906004016118eb565b600061099c611118565b82515181528251602090810151818301528301518160026020020152604083015160608201526109cb816107a5565b9392505050565b60006109dc611136565b8351518152835160209081015190820152835160409081015190820152835160609081015190820152835160809081015190820152610a19611136565b845160a001518152845160c001516020820152845160e00151604080830191909152855161010001516060830152855161012001516080808401919091528151908101909152610a979080610a6d85610b9b565b8152602001610a7b84610b9b565b81526020018660000151815260200186602001518152506107a5565b95945050505050565b6000610acc7f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f00000000000000000000000000000000000000000000000000000000000000008111610b0e57604051630931513d60e11b815260040160405180910390fd5b600b5460405163c15da65b60e01b8152600481018490526001600160a01b039091169063c15da65b90602401600060405180830381600087803b158015610b5457600080fd5b505af1158015610b68573d6000803e3d6000fd5b50506040518492507f1245b881cb30fdad22b2f9fde2d5c2a3605bbdf272d5e8a2235d8c9e81aba2ce9150600090a25050565b604051630926f44b60e31b815260009073d2f6c828606ad8e985008cd825012f269b50cd5890634937a258906107df908590600401611913565b6000610c017f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f00000000000000000000000000000000000000000000000000000000000000008111610c4357604051630931513d60e11b815260040160405180910390fd5b60045460ff1615610c675760405163b703d3c960e01b815260040160405180910390fd5b6004805460ff19166001178155600a546040805163423f3e1960e01b815290516000936001600160a01b039093169263423f3e19928082019260209290918290030181865afa158015610cbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce2919061178c565b60038190559050610cf1611154565b8181527f0000000000000000000000000000000000000000000000000000000000000000602082015260006040820152610d2a81610e10565b600555600a546040805163122db15360e01b815290516000926001600160a01b03169163122db1539160048083019260209291908290030181865afa158015610d77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9b919061178c565b6007819055905060015b818160ff166001901b64ffffffffff161015610dcd5780610dc58161193b565b915050610da5565b6008805460ff191660ff8316179055604051829085907f9f5164261ad26064467dc1be8861f75f2e57ae75579ebb4e500894b0ce9a982390600090a35050505050565b6040516304b98e1d60e31b815260009073f8e637e5c9ec3a8d8fa8843a6df833348e1f1e66906325cc70e8906107df90859060040161195a565b60005460ff1615610e6e576040516342a2e18d60e01b815260040160405180910390fd5b6000805460ff19166001908117909155600680549091019055610e8f6110fa565b7f12817f4161f2f5ded33f26c55735a77e80e4f8975483c8c2704745128417f71181526000602082018190528080610ec684610f6d565b600b54604051631ffc735d60e01b81526004810183905293965091945092506001600160a01b031690631ffc735d906024016020604051808303816000875af1158015610f17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3b919061178c565b507f4be9ef9ae736055964ead1cf3c83a19c8b662b5df2bd4414776bb64d81f75d158383604051610797929190611982565b610f75611172565b60408051808201909152600080825260208201526000610f9361118a565b84518152602080860151828201526040805180820182527f171e826ad4a870fd925e0bf0e87884e70e080879c2205ef10114f28a3b6f6dd781527f2bd407d897fbbca9f88adfd2d15252e69de8c1564eb4d3d27162e259172f1a1d818401528151928301909152828252909450925061100c84846109d2565b93959294505050565b6000806000805160206119bd833981519152848509905060006000805160206119bd833981519152848509905060006000805160206119bd833981519152826000805160206119bd83398151915285620292fc0908905060006000805160206119bd83398151915280846000805160206119bd83398151915287620292f8090960010890506110b382826000805160206119bd8339815191526110bf565b15979650505050505050565b6000838381116110d6576110d383826119a9565b90505b82806110e4576110e4611880565b60006110f08684611779565b0895945050505050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b604051806020016040528061118561118a565b905290565b604051806101400160405280600a906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156111e3576111e36111a9565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611212576112126111a9565b604052919050565b600061014080838503121561122e57600080fd5b604051602080820182811067ffffffffffffffff82111715611252576112526111a9565b806040525081935085601f86011261126957600080fd5b6112716111bf565b92850192808785111561128357600080fd5b865b8581101561129c5780358352918301918301611285565b509092525091949350505050565b6000808284036101808112156112bf57600080fd5b6112c9858561121a565b9250604061013f19820112156112de57600080fd5b50610140830190509250929050565b6000608082840312156112ff57600080fd5b82601f83011261130e57600080fd5b6040516080810181811067ffffffffffffffff82111715611331576113316111a9565b60405280608084018581111561134657600080fd5b845b81811015611360578035835260209283019201611348565b509195945050505050565b6000602080838503121561137e57600080fd5b823567ffffffffffffffff8082111561139657600080fd5b818501915085601f8301126113aa57600080fd5b8135818111156113bc576113bc6111a9565b8060051b91506113cd8483016111e9565b81815291830184019184810190888411156113e757600080fd5b938501935b83851015611405578435825293850193908501906113ec565b98975050505050505050565b6000806040838503121561142457600080fd5b50508035926020909101359150565b6000806000806040858703121561144957600080fd5b843567ffffffffffffffff8082111561146157600080fd5b818701915087601f83011261147557600080fd5b81358181111561148457600080fd5b8860206101408302850101111561149a57600080fd5b6020928301965094509086013590808211156114b557600080fd5b818701915087601f8301126114c957600080fd5b8135818111156114d857600080fd5b8860208260061b85010111156114ed57600080fd5b95989497505060200194505050565b60006040828403121561150e57600080fd5b82601f83011261151d57600080fd5b6040516040810181811067ffffffffffffffff82111715611540576115406111a9565b806040525080604084018581111561134657600080fd5b60006040828403121561156957600080fd5b6040516040810181811067ffffffffffffffff8211171561158c5761158c6111a9565b604052823581526020928301359281019290925250919050565b6000608082840312156115b857600080fd5b6040516060810181811067ffffffffffffffff821117156115db576115db6111a9565b6040526115e88484611557565b815260408301356020820152606083013560408201528091505092915050565b600080610180838503121561161c57600080fd5b611626848461121a565b9150611636846101408501611557565b90509250929050565b60006020828403121561165157600080fd5b5035919050565b600060a0828403121561166a57600080fd5b82601f83011261167957600080fd5b60405160a0810181811067ffffffffffffffff8211171561169c5761169c6111a9565b6040528060a084018581111561134657600080fd5b6000606082840312156116c357600080fd5b82601f8301126116d257600080fd5b6040516060810181811067ffffffffffffffff821117156116f5576116f56111a9565b60405280606084018581111561134657600080fd5b80518260005b600a81101561172f578251825260209283019290910190600101611710565b5050505050565b6101a08101611745828661170a565b83516101408301526020909301516101608201526101800152919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561082057610820611763565b60006020828403121561179e57600080fd5b5051919050565b6000604082840312156117b757600080fd5b6109cb8383611557565b61018081016117d0828561170a565b823561014083015260208301356101608301529392505050565b60808101818360005b60048110156118125781518352602092830192909101906001016117f3565b50505092915050565b815160009082906020808601845b8381101561184557815185529382019390820190600101611829565b50929695505050505050565b6000825160005b818110156118725760208186018101518583015201611858565b506000920191825250919050565b634e487b7160e01b600052601260045260246000fd5b6000826118b357634e487b7160e01b600052601260045260246000fd5b500690565b634e487b7160e01b600052603260045260246000fd5b600061014082840312156118e157600080fd5b6109cb838361121a565b60408101818360005b60028110156118125781518352602092830192909101906001016118f4565b60a08101818360005b600581101561181257815183526020928301929091019060010161191c565b600060ff821660ff810361195157611951611763565b60010192915050565b60608101818360005b6003811015611812578151835260209283019290910190600101611963565b6101808101611991828561170a565b825161014083015260208301516101608301526109cb565b808201808211156108205761082061176356fe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a2646970667358221220ee918fd206d19d51e7802d50e33e7d2078dbfa8fe1f17932de0f7d396db34da864736f6c6343000814003330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020b05cf4195425c165ae56a244284c7021cbf72bfc567d3a39ce7585b26ff50b40a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a000000000000000000000000fcafb222bd61556e393058f08d6d86bdebcce72c000000000000000000000000316a10df1246856609395a43028b6d137fe77280005e3dca15d7169ec424d8df83a9e7b4a43ebde4f20bdecc04897779bcd1573b
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101d95760003560e01c80637028bb0e11610104578063ac98e5df116100a2578063e1c7392a11610071578063e1c7392a14610490578063e33b13a014610498578063edbfe83f146104b5578063fba630f2146104d757600080fd5b8063ac98e5df146103e4578063bc14ee2b1461043a578063bea140b314610474578063c17268d91461048757600080fd5b80638aa0ba92116100de5780638aa0ba921461038f5780639c971729146103b65780639cfced97146103c9578063a28bc38c146103dc57600080fd5b80637028bb0e1461035c5780637d0a81c8146103695780638a2a3dfb1461037c57600080fd5b80634f367f0f1161017c578063623f54ac1161014b578063623f54ac146102f557806362a361bb14610308578063683f3dc31461031b5780636d582d341461033557600080fd5b80634f367f0f146102bb57806358bfc379146102c65780635bb93995146102d95780635d5909dd146102ec57600080fd5b806331e766a5116101b857806331e766a5146102175780633dfb88b21461023a5780634909229f1461024d5780634966efd61461029457600080fd5b8062329f2f146101de5780630f4cf692146101e857806327bea0da14610204575b600080fd5b6101e66104e0565b005b6101f160065481565b6040519081526020015b60405180910390f35b6101e66102123660046112aa565b6105fb565b600154600254610225919082565b604080519283526020830191909152016101fb565b6101f16102483660046112ed565b6107a5565b7f0000000000000000000000000000000000000000000000000000000066b5f85a7f0000000000000000000000000000000000000000000000000000000000002a30610225565b6101f17f000000000000000000000000000000000000000000000000000000000000001981565b600754600654610225565b6101f16102d436600461136b565b610826565b6101f16102e7366004611411565b6108ae565b6101f160075481565b6101e6610303366004611433565b6108d3565b6101f16103163660046114fc565b610958565b610323600a81565b60405160ff90911681526020016101fb565b6101f17f005e3dca15d7169ec424d8df83a9e7b4a43ebde4f20bdecc04897779bcd1573b81565b6008546103239060ff1681565b6101f16103773660046115a6565b610992565b6101f161038a366004611608565b6109d2565b6101f17f01285f3034b91c34dc53f459c13c9bd9ab3079772528ca9e868e550d405ffa7e81565b6101e66103c436600461163f565b610aa0565b6101f16103d7366004611658565b610b9b565b6101e6610bd5565b60095461040d9060ff808216916101008104821691620100008204811691630100000090041684565b6040805160ff958616815293851660208501529184169183019190915290911660608201526080016101fb565b600a54600b54610454916001600160a01b03908116911682565b604080516001600160a01b039384168152929091166020830152016101fb565b6101f16104823660046116b1565b610e10565b6101f160055481565b6101e6610e4a565b6004546104a59060ff1681565b60405190151581526020016101fb565b6104c86104c33660046114fc565b610f6d565b6040516101fb93929190611736565b6101f160035481565b600061050c7f0000000000000000000000000000000000000000000000000000000066b5f85a42611779565b90507f0000000000000000000000000000000000000000000000000000000000002a30811161054e57604051630931513d60e11b815260040160405180910390fd5b600b546009546040516324a47aeb60e01b81526201000090910460ff1660048201526000916001600160a01b0316906324a47aeb906024016020604051808303816000875af11580156105a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c9919061178c565b60405190915081907fc5624680ab5d50c84507f9e0dc2032163de2bda906ab8a661a53dd4d43bd5dc790600090a25050565b60006106277f0000000000000000000000000000000000000000000000000000000066b5f85a42611779565b90507f0000000000000000000000000000000000000000000000000000000000002a3081106106695760405163148fb9a960e31b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000019600654106106ab57604051631ec0b2f760e01b815260040160405180910390fd5b6106ba82356020840135611015565b6106d7576040516379fae7af60e01b815260040160405180910390fd5b60068054600101905560006106f58461038a368690038601866117a5565b600b54604051631ffc735d60e01b8152600481018390529192506001600160a01b031690631ffc735d906024016020604051808303816000875af1158015610741573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610765919061178c565b507f4be9ef9ae736055964ead1cf3c83a19c8b662b5df2bd4414776bb64d81f75d1584846040516107979291906117c1565b60405180910390a150505050565b60405163248f667760e01b8152600090730a0d66bafda8c8838281084d9c3d68dd9a6fc2749063248f6677906107df9085906004016117ea565b602060405180830381865af41580156107fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610820919061178c565b92915050565b60006000805160206119bd83398151915260028360405160200161084a919061181b565b60408051601f198184030181529082905261086491611851565b602060405180830381855afa158015610881573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906108a4919061178c565b6108209190611896565b60006108b86110fa565b838152602081018390526108cb81610958565b949350505050565b8281146108f35760405163ca3487f760e01b815260040160405180910390fd5b8260005b8181101561095057610948868683818110610914576109146118b8565b9050610140020180360381019061092b91906118ce565b85858481811061093d5761093d6118b8565b9050604002016105fb565b6001016108f7565b505050505050565b6040516314d2f97b60e11b81526000907388c2c6a7535463962a34757fe63cc4f296381aba906329a5f2f6906107df9085906004016118eb565b600061099c611118565b82515181528251602090810151818301528301518160026020020152604083015160608201526109cb816107a5565b9392505050565b60006109dc611136565b8351518152835160209081015190820152835160409081015190820152835160609081015190820152835160809081015190820152610a19611136565b845160a001518152845160c001516020820152845160e00151604080830191909152855161010001516060830152855161012001516080808401919091528151908101909152610a979080610a6d85610b9b565b8152602001610a7b84610b9b565b81526020018660000151815260200186602001518152506107a5565b95945050505050565b6000610acc7f0000000000000000000000000000000000000000000000000000000066b5f85a42611779565b90507f0000000000000000000000000000000000000000000000000000000000002a308111610b0e57604051630931513d60e11b815260040160405180910390fd5b600b5460405163c15da65b60e01b8152600481018490526001600160a01b039091169063c15da65b90602401600060405180830381600087803b158015610b5457600080fd5b505af1158015610b68573d6000803e3d6000fd5b50506040518492507f1245b881cb30fdad22b2f9fde2d5c2a3605bbdf272d5e8a2235d8c9e81aba2ce9150600090a25050565b604051630926f44b60e31b815260009073d2f6c828606ad8e985008cd825012f269b50cd5890634937a258906107df908590600401611913565b6000610c017f0000000000000000000000000000000000000000000000000000000066b5f85a42611779565b90507f0000000000000000000000000000000000000000000000000000000000002a308111610c4357604051630931513d60e11b815260040160405180910390fd5b60045460ff1615610c675760405163b703d3c960e01b815260040160405180910390fd5b6004805460ff19166001178155600a546040805163423f3e1960e01b815290516000936001600160a01b039093169263423f3e19928082019260209290918290030181865afa158015610cbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce2919061178c565b60038190559050610cf1611154565b8181527f005e3dca15d7169ec424d8df83a9e7b4a43ebde4f20bdecc04897779bcd1573b602082015260006040820152610d2a81610e10565b600555600a546040805163122db15360e01b815290516000926001600160a01b03169163122db1539160048083019260209291908290030181865afa158015610d77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9b919061178c565b6007819055905060015b818160ff166001901b64ffffffffff161015610dcd5780610dc58161193b565b915050610da5565b6008805460ff191660ff8316179055604051829085907f9f5164261ad26064467dc1be8861f75f2e57ae75579ebb4e500894b0ce9a982390600090a35050505050565b6040516304b98e1d60e31b815260009073f8e637e5c9ec3a8d8fa8843a6df833348e1f1e66906325cc70e8906107df90859060040161195a565b60005460ff1615610e6e576040516342a2e18d60e01b815260040160405180910390fd5b6000805460ff19166001908117909155600680549091019055610e8f6110fa565b7f12817f4161f2f5ded33f26c55735a77e80e4f8975483c8c2704745128417f71181526000602082018190528080610ec684610f6d565b600b54604051631ffc735d60e01b81526004810183905293965091945092506001600160a01b031690631ffc735d906024016020604051808303816000875af1158015610f17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3b919061178c565b507f4be9ef9ae736055964ead1cf3c83a19c8b662b5df2bd4414776bb64d81f75d158383604051610797929190611982565b610f75611172565b60408051808201909152600080825260208201526000610f9361118a565b84518152602080860151828201526040805180820182527f171e826ad4a870fd925e0bf0e87884e70e080879c2205ef10114f28a3b6f6dd781527f2bd407d897fbbca9f88adfd2d15252e69de8c1564eb4d3d27162e259172f1a1d818401528151928301909152828252909450925061100c84846109d2565b93959294505050565b6000806000805160206119bd833981519152848509905060006000805160206119bd833981519152848509905060006000805160206119bd833981519152826000805160206119bd83398151915285620292fc0908905060006000805160206119bd83398151915280846000805160206119bd83398151915287620292f8090960010890506110b382826000805160206119bd8339815191526110bf565b15979650505050505050565b6000838381116110d6576110d383826119a9565b90505b82806110e4576110e4611880565b60006110f08684611779565b0895945050505050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b604051806020016040528061118561118a565b905290565b604051806101400160405280600a906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156111e3576111e36111a9565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611212576112126111a9565b604052919050565b600061014080838503121561122e57600080fd5b604051602080820182811067ffffffffffffffff82111715611252576112526111a9565b806040525081935085601f86011261126957600080fd5b6112716111bf565b92850192808785111561128357600080fd5b865b8581101561129c5780358352918301918301611285565b509092525091949350505050565b6000808284036101808112156112bf57600080fd5b6112c9858561121a565b9250604061013f19820112156112de57600080fd5b50610140830190509250929050565b6000608082840312156112ff57600080fd5b82601f83011261130e57600080fd5b6040516080810181811067ffffffffffffffff82111715611331576113316111a9565b60405280608084018581111561134657600080fd5b845b81811015611360578035835260209283019201611348565b509195945050505050565b6000602080838503121561137e57600080fd5b823567ffffffffffffffff8082111561139657600080fd5b818501915085601f8301126113aa57600080fd5b8135818111156113bc576113bc6111a9565b8060051b91506113cd8483016111e9565b81815291830184019184810190888411156113e757600080fd5b938501935b83851015611405578435825293850193908501906113ec565b98975050505050505050565b6000806040838503121561142457600080fd5b50508035926020909101359150565b6000806000806040858703121561144957600080fd5b843567ffffffffffffffff8082111561146157600080fd5b818701915087601f83011261147557600080fd5b81358181111561148457600080fd5b8860206101408302850101111561149a57600080fd5b6020928301965094509086013590808211156114b557600080fd5b818701915087601f8301126114c957600080fd5b8135818111156114d857600080fd5b8860208260061b85010111156114ed57600080fd5b95989497505060200194505050565b60006040828403121561150e57600080fd5b82601f83011261151d57600080fd5b6040516040810181811067ffffffffffffffff82111715611540576115406111a9565b806040525080604084018581111561134657600080fd5b60006040828403121561156957600080fd5b6040516040810181811067ffffffffffffffff8211171561158c5761158c6111a9565b604052823581526020928301359281019290925250919050565b6000608082840312156115b857600080fd5b6040516060810181811067ffffffffffffffff821117156115db576115db6111a9565b6040526115e88484611557565b815260408301356020820152606083013560408201528091505092915050565b600080610180838503121561161c57600080fd5b611626848461121a565b9150611636846101408501611557565b90509250929050565b60006020828403121561165157600080fd5b5035919050565b600060a0828403121561166a57600080fd5b82601f83011261167957600080fd5b60405160a0810181811067ffffffffffffffff8211171561169c5761169c6111a9565b6040528060a084018581111561134657600080fd5b6000606082840312156116c357600080fd5b82601f8301126116d257600080fd5b6040516060810181811067ffffffffffffffff821117156116f5576116f56111a9565b60405280606084018581111561134657600080fd5b80518260005b600a81101561172f578251825260209283019290910190600101611710565b5050505050565b6101a08101611745828661170a565b83516101408301526020909301516101608201526101800152919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561082057610820611763565b60006020828403121561179e57600080fd5b5051919050565b6000604082840312156117b757600080fd5b6109cb8383611557565b61018081016117d0828561170a565b823561014083015260208301356101608301529392505050565b60808101818360005b60048110156118125781518352602092830192909101906001016117f3565b50505092915050565b815160009082906020808601845b8381101561184557815185529382019390820190600101611829565b50929695505050505050565b6000825160005b818110156118725760208186018101518583015201611858565b506000920191825250919050565b634e487b7160e01b600052601260045260246000fd5b6000826118b357634e487b7160e01b600052601260045260246000fd5b500690565b634e487b7160e01b600052603260045260246000fd5b600061014082840312156118e157600080fd5b6109cb838361121a565b60408101818360005b60028110156118125781518352602092830192909101906001016118f4565b60a08101818360005b600581101561181257815183526020928301929091019060010161191c565b600060ff821660ff810361195157611951611763565b60010192915050565b60608101818360005b6003811015611812578151835260209283019290910190600101611963565b6101808101611991828561170a565b825161014083015260208301516101608301526109cb565b808201808211156108205761082061176356fe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a2646970667358221220ee918fd206d19d51e7802d50e33e7d2078dbfa8fe1f17932de0f7d396db34da864736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020b05cf4195425c165ae56a244284c7021cbf72bfc567d3a39ce7585b26ff50b40a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a000000000000000000000000fcafb222bd61556e393058f08d6d86bdebcce72c000000000000000000000000316a10df1246856609395a43028b6d137fe77280005e3dca15d7169ec424d8df83a9e7b4a43ebde4f20bdecc04897779bcd1573b
-----Decoded View---------------
Arg [0] : _duration (uint256): 10800
Arg [1] : _treeDepths (tuple):
Arg [1] : intStateTreeDepth (uint8): 1
Arg [2] : messageTreeSubDepth (uint8): 1
Arg [3] : messageTreeDepth (uint8): 2
Arg [4] : voteOptionTreeDepth (uint8): 2
Arg [2] : _coordinatorPubKey (tuple):
Arg [1] : x (uint256): 4985705999348971467685965754290681885892560671835589495445295887331402666164
Arg [2] : y (uint256): 4574198666043287793706844951217120352389375266244797367173489160961916667546
Arg [3] : _extContracts (tuple):
Arg [1] : maci (address): 0xfcaFB222bd61556E393058F08d6d86bdEbcCE72c
Arg [2] : messageAq (address): 0x316A10Df1246856609395A43028B6d137fe77280
Arg [4] : _emptyBallotRoot (uint256): 166510078825589460025300915201657086611944528317298994959376081297530246971
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000002a30
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [5] : 0b05cf4195425c165ae56a244284c7021cbf72bfc567d3a39ce7585b26ff50b4
Arg [6] : 0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a
Arg [7] : 000000000000000000000000fcafb222bd61556e393058f08d6d86bdebcce72c
Arg [8] : 000000000000000000000000316a10df1246856609395a43028b6d137fe77280
Arg [9] : 005e3dca15d7169ec424d8df83a9e7b4a43ebde4f20bdecc04897779bcd1573b
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.