Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Latest 3 from a total of 3 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Deploy Poll | 241123684 | 466 days ago | IN | 0 ETH | 0.0000772 | ||||
| Deploy Poll | 241094545 | 466 days ago | IN | 0 ETH | 0.00042333 | ||||
| 0x61016060 | 241094519 | 466 days ago | IN | 0 ETH | 0.00017253 |
Cross-Chain Transactions
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:
MACI
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 { IPollFactory } from "./interfaces/IPollFactory.sol";
import { IMessageProcessorFactory } from "./interfaces/IMPFactory.sol";
import { ITallyFactory } from "./interfaces/ITallyFactory.sol";
import { InitialVoiceCreditProxy } from "./initialVoiceCreditProxy/InitialVoiceCreditProxy.sol";
import { SignUpGatekeeper } from "./gatekeepers/SignUpGatekeeper.sol";
import { IMACI } from "./interfaces/IMACI.sol";
import { Params } from "./utilities/Params.sol";
import { Utilities } from "./utilities/Utilities.sol";
import { DomainObjs } from "./utilities/DomainObjs.sol";
import { CurveBabyJubJub } from "./crypto/BabyJubJub.sol";
import { InternalLazyIMT, LazyIMTData } from "./trees/LazyIMT.sol";
/// @title MACI - Minimum Anti-Collusion Infrastructure Version 1
/// @notice A contract which allows users to sign up, and deploy new polls
contract MACI is IMACI, DomainObjs, Params, Utilities {
/// @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. 2 ** 23 = 8388608
/// this should also match the parameter of the circom circuits.
/// @notice IMPORTANT: remember to change the ballot tree depth
/// in contracts/ts/genEmptyBallotRootsContract.ts file
/// if we change the state tree depth!
uint8 public immutable stateTreeDepth;
uint256 public immutable maxSignups;
uint8 internal constant TREE_ARITY = 2;
/// @notice The hash of a blank state leaf
uint256 internal constant BLANK_STATE_LEAF_HASH =
uint256(6769006970205099520508948723718471724660867171122235270773600567925038008762);
/// @notice The roots of the empty ballot trees
uint256[5] public emptyBallotRoots;
/// @notice Each poll has an incrementing ID
uint256 public nextPollId;
/// @notice A mapping of poll IDs to Poll contracts.
mapping(uint256 => PollContracts) public polls;
/// @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 tree. Represents a mapping between each user's public key
/// and their voice credit balance.
LazyIMTData public lazyIMTData;
/// @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,
Mode _mode
);
/// @notice custom errors
error PoseidonHashLibrariesNotLinked();
error TooManySignups();
error InvalidPubKey();
error PollDoesNotExist(uint256 pollId);
/// @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 _stateTreeDepth The depth of the state tree
/// @param _emptyBallotRoots The roots of the empty ballot trees
constructor(
IPollFactory _pollFactory,
IMessageProcessorFactory _messageProcessorFactory,
ITallyFactory _tallyFactory,
SignUpGatekeeper _signUpGatekeeper,
InitialVoiceCreditProxy _initialVoiceCreditProxy,
uint8 _stateTreeDepth,
uint256[5] memory _emptyBallotRoots
) payable {
// initialize and insert the blank leaf
InternalLazyIMT._init(lazyIMTData, _stateTreeDepth);
InternalLazyIMT._insert(lazyIMTData, BLANK_STATE_LEAF_HASH);
pollFactory = _pollFactory;
messageProcessorFactory = _messageProcessorFactory;
tallyFactory = _tallyFactory;
signUpGatekeeper = _signUpGatekeeper;
initialVoiceCreditProxy = _initialVoiceCreditProxy;
stateTreeDepth = _stateTreeDepth;
maxSignups = uint256(TREE_ARITY) ** uint256(_stateTreeDepth);
emptyBallotRoots = _emptyBallotRoots;
// 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 {
// ensure we do not have more signups than what the circuits support
if (lazyIMTData.numberOfLeaves >= maxSignups) revert TooManySignups();
// ensure that the public key is on the baby jubjub curve
if (!CurveBabyJubJub.isOnCurve(_pubKey.x, _pubKey.y)) {
revert InvalidPubKey();
}
// 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 insert it into the tree.
uint256 stateLeaf = hashStateLeaf(StateLeaf(_pubKey, voiceCreditBalance, timestamp));
InternalLazyIMT._insert(lazyIMTData, stateLeaf);
emit SignUp(lazyIMTData.numberOfLeaves - 1, _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
function deployPoll(
uint256 _duration,
TreeDepths memory _treeDepths,
PubKey memory _coordinatorPubKey,
address _verifier,
address _vkRegistry,
Mode _mode
) public virtual {
// 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++;
}
// check coordinator key is a valid point on the curve
if (!CurveBabyJubJub.isOnCurve(_coordinatorPubKey.x, _coordinatorPubKey.y)) {
revert InvalidPubKey();
}
uint256 voteOptionTreeDepth = _treeDepths.voteOptionTreeDepth;
address p = pollFactory.deploy(
_duration,
_treeDepths,
_coordinatorPubKey,
address(this),
emptyBallotRoots[voteOptionTreeDepth - 1]
);
address mp = messageProcessorFactory.deploy(_verifier, _vkRegistry, p, msg.sender, _mode);
address tally = tallyFactory.deploy(_verifier, _vkRegistry, p, mp, msg.sender, _mode);
// store the addresses in a struct so they can be returned
PollContracts memory pollAddr = PollContracts({ poll: p, messageProcessor: mp, tally: tally });
polls[pollId] = pollAddr;
emit DeployPoll(pollId, _coordinatorPubKey.x, _coordinatorPubKey.y, _mode);
}
/// @inheritdoc IMACI
function getStateTreeRoot() public view returns (uint256 root) {
root = InternalLazyIMT._root(lazyIMTData);
}
/// @notice Get the Poll details
/// @param _pollId The identifier of the Poll to retrieve
/// @return pollContracts The Poll contract object
function getPoll(uint256 _pollId) public view returns (PollContracts memory pollContracts) {
if (_pollId >= nextPollId) revert PollDoesNotExist(_pollId);
pollContracts = polls[_pollId];
}
/// @inheritdoc IMACI
function numSignUps() public view returns (uint256 signUps) {
signUps = lazyIMTData.numberOfLeaves;
}
}// 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
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;
/// @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 SignUpGatekeeper
/// @notice A gatekeeper contract which allows users to sign up for a poll.
abstract contract SignUpGatekeeper {
/// @notice Allows to set the MACI contract
// solhint-disable-next-line no-empty-blocks
function setMaciInstance(address _maci) public virtual {}
/// @notice Registers the user
/// @param _user The address of the user
/// @param _data additional data
// solhint-disable-next-line no-empty-blocks
function register(address _user, bytes memory _data) public virtual {}
/// @notice Get the trait of the gatekeeper
/// @return The type of the gatekeeper
function getTrait() public pure virtual returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title InitialVoiceCreditProxy
/// @notice This contract is the base contract for
/// InitialVoiceCreditProxy contracts. It allows to set a custom initial voice
/// credit balance for MACI's voters.
abstract contract InitialVoiceCreditProxy {
/// @notice Returns the initial voice credit balance for a new MACI's voter
/// @param _user the address of the voter
/// @param _data additional data
/// @return the balance
// solhint-disable-next-line no-empty-blocks
function getVoiceCredits(address _user, bytes memory _data) public view virtual returns (uint256) {}
}// 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";
/// @title IMessageProcessorFactory
/// @notice MessageProcessorFactory interface
interface IMessageProcessorFactory {
/// @notice Deploy a new MessageProcessor contract and return the address.
/// @param _verifier Verifier contract
/// @param _vkRegistry VkRegistry contract
/// @param _poll Poll contract
/// @param _owner Owner of the MessageProcessor contract
/// @param _mode Voting mode
/// @return The deployed MessageProcessor contract
function deploy(
address _verifier,
address _vkRegistry,
address _poll,
address _owner,
DomainObjs.Mode _mode
) external returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import { Params } from "../utilities/Params.sol";
import { DomainObjs } from "../utilities/DomainObjs.sol";
/// @title IPollFactory
/// @notice PollFactory interface
interface IPollFactory {
/// @notice Deploy a new Poll contract and AccQueue contract for messages.
/// @param _duration The duration of the poll
/// @param _treeDepths The depths of the merkle trees
/// @param _coordinatorPubKey The coordinator's public key
/// @param _maci The MACI contract interface reference
/// @param _emptyBallotRoot The root of the empty ballot tree
/// @return The deployed Poll contract
function deploy(
uint256 _duration,
Params.TreeDepths memory _treeDepths,
DomainObjs.PubKey memory _coordinatorPubKey,
address _maci,
uint256 _emptyBallotRoot
) external returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import { DomainObjs } from "../utilities/DomainObjs.sol";
/// @title ITallyFactory
/// @notice TallyFactory interface
interface ITallyFactory {
/// @notice Deploy a new Tally contract and return the address.
/// @param _verifier Verifier contract
/// @param _vkRegistry VkRegistry contract
/// @param _poll Poll contract
/// @param _messageProcessor MessageProcessor contract
/// @param _owner Owner of the contract
/// @param _mode Voting mode
/// @return The deployed contract
function deploy(
address _verifier,
address _vkRegistry,
address _poll,
address _messageProcessor,
address _owner,
DomainObjs.Mode _mode
) external returns (address);
}// 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;
import { PoseidonT3 } from "../crypto/PoseidonT3.sol";
/// @notice A struct that holds a LazyIMT data
struct LazyIMTData {
uint40 maxIndex;
uint40 numberOfLeaves;
mapping(uint256 => uint256) elements;
}
/// @notice Custom errors
error DefaultZeroBadIndex();
error DepthTooLarge();
error DepthCannotBeZero();
error NumberOfLeavesCannotBeZero();
error AmbiguousDepth();
/// @title InternalLazyIMT
/// @dev A LazyIMT with Zeroes value set to the hash of
/// a MACI Blank State Leaf
/// @notice This implementation is taken from zk-kit
/// https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/imt.sol/contracts/internal/InternalLazyIMT.sol
/// and modified to work with MACI.
library InternalLazyIMT {
uint256 internal constant MAX_DEPTH = 32;
uint40 internal constant MAX_INDEX = (1 << 32) - 1;
uint256 internal constant Z_0 = 6769006970205099520508948723718471724660867171122235270773600567925038008762;
uint256 internal constant Z_1 = 2972820301952105722688860985556183033855705951263221082702981787813754939537;
uint256 internal constant Z_2 = 19009473369953096352828532459942637819279786575057870804186038131433538383332;
uint256 internal constant Z_3 = 1877001762518233819645599208989578372605193385355680834239714249281096297174;
uint256 internal constant Z_4 = 4022598852800694816938652741439614774645858989706174527409714109784047480520;
uint256 internal constant Z_5 = 8078617093048295855521451309865989496051030103472138252021705658681696298712;
uint256 internal constant Z_6 = 21861637049723057871988413507302821095913894718242489848472531680353400271584;
uint256 internal constant Z_7 = 2969626195902860050407584814596940245443093107470116547781577350415736914038;
uint256 internal constant Z_8 = 13863086449569754493134198846069090996475357615094865751949144794620598051673;
uint256 internal constant Z_9 = 13774233155966252113965527228795435224641075024674384267997743867571011718458;
uint256 internal constant Z_10 = 7674682532432601125535053858292577379388329393276537570517515727197672122157;
uint256 internal constant Z_11 = 2657471847139856346360223652201172662911313292042510535836997980857168085414;
uint256 internal constant Z_12 = 14112562742724116016492623819773686970029672095023612838615540190985426106768;
uint256 internal constant Z_13 = 16966520284141749853106006448832965932249937855809150844697400390499975107456;
uint256 internal constant Z_14 = 21146121663662200258116396149536742745305242191891337170899444969488030502620;
uint256 internal constant Z_15 = 8395571901509192935479743034608666551563743095742598750914087478677907730358;
uint256 internal constant Z_16 = 11584898446168752024843587018551921614604785083342073076015560385003528300499;
uint256 internal constant Z_17 = 19681365563800708744156562671961079617734353445922751560400662591064339349816;
uint256 internal constant Z_18 = 11060693795061987995391612467169498625108376769265861980249917517984263067473;
uint256 internal constant Z_19 = 20136055137568042031318427040358591430196153124171666293804511634641041409480;
uint256 internal constant Z_20 = 10438448879123510479428288344427042332522761183009746406441238260861529360499;
uint256 internal constant Z_21 = 20302411580043873005239406811066876697276902025885155920151067303221158887923;
uint256 internal constant Z_22 = 16905699456770804689394621400052823445587122726651394178036372609288266146575;
uint256 internal constant Z_23 = 13317924909658910751179983108234689413063120680580702936091220805509299490708;
uint256 internal constant Z_24 = 11624463897690689883938167321830091369950933831231839575225419984927228390345;
uint256 internal constant Z_25 = 12388077003631746290497429926117583834311703848735670874049584990731919769551;
uint256 internal constant Z_26 = 16641943593086083573943184041147806885253724243247212515325749241831788827569;
uint256 internal constant Z_27 = 8675770901378242337954792996483564563211065498082968464791979179678744114204;
uint256 internal constant Z_28 = 3741944068643598116715410464277276913339851849923986024648161859457213369743;
uint256 internal constant Z_29 = 9365051374992868354747065577256691008852056444829383197903446097138255771103;
uint256 internal constant Z_30 = 19608043542461863702809013760105552654336523908709289008189330402608282498922;
uint256 internal constant Z_31 = 15116478429455923389320892447700153271977917184085737305957533984219061034768;
uint256 internal constant Z_32 = 13372161856163346716845871420623647679532631520878788090782842562075678687737;
/// @notice Returns the default zero value for a given index
/// @param index The index of the zero value
/// @return The zero value
function _defaultZero(uint8 index) internal pure returns (uint256) {
if (index == 0) return Z_0;
if (index == 1) return Z_1;
if (index == 2) return Z_2;
if (index == 3) return Z_3;
if (index == 4) return Z_4;
if (index == 5) return Z_5;
if (index == 6) return Z_6;
if (index == 7) return Z_7;
if (index == 8) return Z_8;
if (index == 9) return Z_9;
if (index == 10) return Z_10;
if (index == 11) return Z_11;
if (index == 12) return Z_12;
if (index == 13) return Z_13;
if (index == 14) return Z_14;
if (index == 15) return Z_15;
if (index == 16) return Z_16;
if (index == 17) return Z_17;
if (index == 18) return Z_18;
if (index == 19) return Z_19;
if (index == 20) return Z_20;
if (index == 21) return Z_21;
if (index == 22) return Z_22;
if (index == 23) return Z_23;
if (index == 24) return Z_24;
if (index == 25) return Z_25;
if (index == 26) return Z_26;
if (index == 27) return Z_27;
if (index == 28) return Z_28;
if (index == 29) return Z_29;
if (index == 30) return Z_30;
if (index == 31) return Z_31;
if (index == 32) return Z_32;
revert DefaultZeroBadIndex();
}
/// @notice Initializes the LazyIMT
/// @param self The LazyIMTData
/// @param depth The depth of the tree
function _init(LazyIMTData storage self, uint8 depth) internal {
if (depth > MAX_DEPTH) {
revert DepthTooLarge();
}
self.maxIndex = uint40((1 << depth) - 1);
self.numberOfLeaves = 0;
}
/// @notice Returns the index for a given level and index
/// @param level The level
/// @param index The index
/// @return The index for the element
function _indexForElement(uint8 level, uint40 index) internal pure returns (uint40) {
// store the elements sparsely
return (uint40(level) << 32) - level + index;
}
/// @notice Inserts a leaf into the LazyIMT
/// @param self The LazyIMTData
/// @param leaf The leaf to insert
function _insert(LazyIMTData storage self, uint256 leaf) internal {
uint40 index = self.numberOfLeaves;
self.numberOfLeaves = index + 1;
uint256 hash = leaf;
for (uint8 i = 0; ; ) {
self.elements[_indexForElement(i, index)] = hash;
// it's a left element so we don't hash until there's a right element
if (index & 1 == 0) break;
uint40 elementIndex = _indexForElement(i, index - 1);
hash = PoseidonT3.poseidon([self.elements[elementIndex], hash]);
unchecked {
index >>= 1;
i++;
}
}
}
/// @notice Returns the root of the LazyIMT
/// @param self The LazyIMTData
/// @return The root of the LazyIMT
function _root(LazyIMTData storage self) internal view returns (uint256) {
// this will always short circuit if self.numberOfLeaves == 0
uint40 numberOfLeaves = self.numberOfLeaves;
// dynamically determine a depth
uint8 depth = 1;
while (uint40(1 << depth) < numberOfLeaves) {
depth++;
}
return _root(self, numberOfLeaves, depth);
}
/// @notice Returns the root of the LazyIMT
/// @dev Here it's assumed that the depth value is valid.
/// If it is either 0 or > 2^8-1 this function will panic.
/// @param self The LazyIMTData
/// @param numberOfLeaves The number of leaves
/// @param depth The depth of the tree
/// @return The root of the LazyIMT
function _root(LazyIMTData storage self, uint40 numberOfLeaves, uint8 depth) internal view returns (uint256) {
if (depth > MAX_DEPTH) {
revert DepthTooLarge();
}
// this should always short circuit if self.numberOfLeaves == 0
if (numberOfLeaves == 0) return _defaultZero(depth);
uint256[] memory levels = new uint256[](depth + 1);
_levels(self, numberOfLeaves, depth, levels);
return levels[depth];
}
/// @notice Updates the levels of the LazyIMT
/// @param self The LazyIMTData
/// @param numberOfLeaves The number of leaves
/// @param depth The depth of the tree
/// @param levels The levels of the tree
function _levels(
LazyIMTData storage self,
uint40 numberOfLeaves,
uint8 depth,
uint256[] memory levels
) internal view {
if (depth > MAX_DEPTH) {
revert DepthTooLarge();
}
if (numberOfLeaves == 0) {
revert NumberOfLeavesCannotBeZero();
}
// this should always short circuit if self.numberOfLeaves == 0
uint40 index = numberOfLeaves - 1;
if (index & 1 == 0) {
levels[0] = self.elements[_indexForElement(0, index)];
} else {
levels[0] = _defaultZero(0);
}
for (uint8 i = 0; i < depth; ) {
if (index & 1 == 0) {
levels[i + 1] = PoseidonT3.poseidon([levels[i], _defaultZero(i)]);
} else {
uint256 levelCount = (numberOfLeaves) >> (i + 1);
if (levelCount > index >> 1) {
uint256 parent = self.elements[_indexForElement(i + 1, index >> 1)];
levels[i + 1] = parent;
} else {
uint256 sibling = self.elements[_indexForElement(i, index - 1)];
levels[i + 1] = PoseidonT3.poseidon([sibling, levels[i]]);
}
}
unchecked {
index >>= 1;
i++;
}
}
}
}// 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": "0x2f1398ab5e322d357df8cdd2e7ba73122c5fdda4"
},
"contracts/crypto/PoseidonT4.sol": {
"PoseidonT4": "0x8778da47ef619f56341fe95514e95fa0ff3b77c6"
},
"contracts/crypto/PoseidonT5.sol": {
"PoseidonT5": "0xb8bc2c7cf71441ff7e6f111d3457e3d61c564968"
},
"contracts/crypto/PoseidonT6.sol": {
"PoseidonT6": "0x37282fede56aa1d7266ecb12dc3b342d12044e2e"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IPollFactory","name":"_pollFactory","type":"address"},{"internalType":"contract IMessageProcessorFactory","name":"_messageProcessorFactory","type":"address"},{"internalType":"contract ITallyFactory","name":"_tallyFactory","type":"address"},{"internalType":"contract SignUpGatekeeper","name":"_signUpGatekeeper","type":"address"},{"internalType":"contract InitialVoiceCreditProxy","name":"_initialVoiceCreditProxy","type":"address"},{"internalType":"uint8","name":"_stateTreeDepth","type":"uint8"},{"internalType":"uint256[5]","name":"_emptyBallotRoots","type":"uint256[5]"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"DefaultZeroBadIndex","type":"error"},{"inputs":[],"name":"DepthTooLarge","type":"error"},{"inputs":[],"name":"InvalidMessage","type":"error"},{"inputs":[],"name":"InvalidPubKey","type":"error"},{"inputs":[],"name":"NumberOfLeavesCannotBeZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"pollId","type":"uint256"}],"name":"PollDoesNotExist","type":"error"},{"inputs":[],"name":"PoseidonHashLibrariesNotLinked","type":"error"},{"inputs":[],"name":"TooManySignups","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_pollId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_coordinatorPubKeyX","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_coordinatorPubKeyY","type":"uint256"},{"indexed":false,"internalType":"enum DomainObjs.Mode","name":"_mode","type":"uint8"}],"name":"DeployPoll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_stateIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_userPubKeyX","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_userPubKeyY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_voiceCreditBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"SignUp","type":"event"},{"inputs":[],"name":"MESSAGE_DATA_LENGTH","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"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"},{"internalType":"address","name":"_verifier","type":"address"},{"internalType":"address","name":"_vkRegistry","type":"address"},{"internalType":"enum DomainObjs.Mode","name":"_mode","type":"uint8"}],"name":"deployPoll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"emptyBallotRoots","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pollId","type":"uint256"}],"name":"getPoll","outputs":[{"components":[{"internalType":"address","name":"poll","type":"address"},{"internalType":"address","name":"messageProcessor","type":"address"},{"internalType":"address","name":"tally","type":"address"}],"internalType":"struct MACI.PollContracts","name":"pollContracts","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStateTreeRoot","outputs":[{"internalType":"uint256","name":"root","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":"initialVoiceCreditProxy","outputs":[{"internalType":"contract InitialVoiceCreditProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lazyIMTData","outputs":[{"internalType":"uint40","name":"maxIndex","type":"uint40"},{"internalType":"uint40","name":"numberOfLeaves","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSignups","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageProcessorFactory","outputs":[{"internalType":"contract IMessageProcessorFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextPollId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numSignUps","outputs":[{"internalType":"uint256","name":"signUps","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":[],"name":"pollFactory","outputs":[{"internalType":"contract IPollFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"polls","outputs":[{"internalType":"address","name":"poll","type":"address"},{"internalType":"address","name":"messageProcessor","type":"address"},{"internalType":"address","name":"tally","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"array","type":"uint256[]"}],"name":"sha256Hash","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct DomainObjs.PubKey","name":"_pubKey","type":"tuple"},{"internalType":"bytes","name":"_signUpGatekeeperData","type":"bytes"},{"internalType":"bytes","name":"_initialVoiceCreditProxyData","type":"bytes"}],"name":"signUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signUpGatekeeper","outputs":[{"internalType":"contract SignUpGatekeeper","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stateTreeDepth","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tallyFactory","outputs":[{"internalType":"contract ITallyFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61016060405260405162002eab38038062002eab8339810160408190526200002791620003f5565b62000034600783620000ff565b6200006160077f0ef71f46e11a513c599eed9dd03576c33439bcfb1cee155316f90541e41649ba62000155565b6001600160a01b0380881660c05286811660e052858116610100528481166101205283166101405260ff821660808190526200009f90600262000618565b60a052620000b160008260056200036c565b506040805180820190915260018082526020820152620000d190620002b6565b600003620000f257604051633d7ba68560e21b815260040160405180910390fd5b50505050505050620006d2565b60208160ff1611156200012557604051633e104c7760e01b815260040160405180910390fd5b62000138600160ff831681901b62000626565b82546001600160501b03191664ffffffffff919091161790915550565b815465010000000000900464ffffffffff16620001748160016200063c565b835464ffffffffff91909116650100000000000264ffffffffff60281b199091161783558160005b81600186016000620001af84876200033c565b64ffffffffff1681526020810191909152604001600020556001831615620002af576000620001eb82620001e560018762000664565b6200033c565b60408051808201825264ffffffffff8316600090815260018a01602090815290839020548252810186905290516314d2f97b60e11b8152919250732f1398ab5e322d357df8cdd2e7ba73122c5fdda4916329a5f2f6916200024f9160040162000685565b602060405180830381865af41580156200026d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002939190620006b8565b647fffffffff600195861c16949093509190910190506200019c565b5050505050565b6040516314d2f97b60e11b8152600090732f1398ab5e322d357df8cdd2e7ba73122c5fdda4906329a5f2f690620002f290859060040162000685565b602060405180830381865af415801562000310573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003369190620006b8565b92915050565b6000816200035960ff851664ff00000000602087901b1662000664565b6200036591906200063c565b9392505050565b82600581019282156200039d579160200282015b828111156200039d57825182559160200191906001019062000380565b50620003ab929150620003af565b5090565b5b80821115620003ab5760008155600101620003b0565b6001600160a01b0381168114620003dc57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b600080600080600080600061016080898b0312156200041357600080fd5b88516200042081620003c6565b809850506020808a01516200043581620003c6565b60408b01519098506200044881620003c6565b60608b01519097506200045b81620003c6565b60808b01519096506200046e81620003c6565b60a08b015190955060ff811681146200048657600080fd5b935060df8a018b136200049857600080fd5b60405160a081016001600160401b0381118282101715620004bd57620004bd620003df565b604052918a0191808c841115620004d357600080fd5b60c08c015b84811015620004f15780518252908301908301620004d8565b505080935050505092959891949750929550565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156200055c57816000190482111562000540576200054062000505565b808516156200054e57918102915b93841c939080029062000520565b509250929050565b600082620005755750600162000336565b81620005845750600062000336565b81600181146200059d5760028114620005a857620005c8565b600191505062000336565b60ff841115620005bc57620005bc62000505565b50506001821b62000336565b5060208310610133831016604e8410600b8410161715620005ed575081810a62000336565b620005f983836200051b565b806000190482111562000610576200061062000505565b029392505050565b600062000365838362000564565b8181038181111562000336576200033662000505565b64ffffffffff8181168382160190808211156200065d576200065d62000505565b5092915050565b64ffffffffff8281168282160390808211156200065d576200065d62000505565b60408101818360005b6002811015620006af5781518352602092830192909101906001016200068e565b50505092915050565b600060208284031215620006cb57600080fd5b5051919050565b60805160a05160c05160e05161010051610120516101405161275462000757600039600081816103b501526106900152600081816101dc015261060e0152600081816103010152610ac70152600081816101980152610a2c015260008181610286015261097c0152600081816104a2015261057c0152600061032801526127546000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c8063652c76e4116100de578063aab4a67011610097578063b87802c811610071578063b87802c814610477578063bea140b31461048a578063df82635a1461049d578063edbfe83f146104c457600080fd5b8063aab4a670146103b0578063ac2f0074146103d7578063b68687201461043d57600080fd5b8063652c76e414610323578063683f3dc31461035c5780636b4575e2146103645780637d0a81c8146103775780638a2a3dfb1461038a5780639cfced971461039d57600080fd5b8063343393b51161014b57806358bfc3791161012557806358bfc379146102c35780635bb93995146102d657806362a361bb146102e957806362b31f1e146102fc57600080fd5b8063343393b5146102815780633dfb88b2146102a8578063423f3e19146102bb57600080fd5b8063055575eb14610193578063079410db146101d7578063122db153146101fe5780631a8cbcaa1461021e5780632b786571146102635780633364120a1461026c575b600080fd5b6101ba7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6101ba7f000000000000000000000000000000000000000000000000000000000000000081565b600754600160281b900464ffffffffff165b6040519081526020016101ce565b61023161022c366004611cab565b6104e6565b6040805182516001600160a01b03908116825260208085015182169083015292820151909216908201526060016101ce565b61021060055481565b61027f61027a366004611df0565b610577565b005b6101ba7f000000000000000000000000000000000000000000000000000000000000000081565b6102106102b6366004611e64565b6107b6565b610210610837565b6102106102d1366004611ee1565b610848565b6102106102e4366004611f86565b6108d0565b6102106102f7366004611fa8565b6108f5565b6101ba7f000000000000000000000000000000000000000000000000000000000000000081565b61034a7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016101ce565b61034a600a81565b61027f61037236600461204a565b61092f565b610210610385366004612129565b610c29565b61021061039836600461218a565b610c69565b6102106103ab366004612238565b610d37565b6101ba7f000000000000000000000000000000000000000000000000000000000000000081565b6104136103e5366004611cab565b6006602052600090815260409020805460018201546002909201546001600160a01b03918216928216911683565b604080516001600160a01b03948516815292841660208401529216918101919091526060016101ce565b6007546104599064ffffffffff80821691600160281b90041682565b6040805164ffffffffff9384168152929091166020830152016101ce565b610210610485366004611cab565b610d71565b610210610498366004612290565b610d88565b6102107f000000000000000000000000000000000000000000000000000000000000000081565b6104d76104d2366004611fa8565b610dc2565b6040516101ce939291906122e8565b6040805160608101825260008082526020820181905291810191909152600554821061052c5760405163a86ecdd560e01b81526004810183905260240160405180910390fd5b50600090815260066020908152604091829020825160608101845281546001600160a01b03908116825260018301548116938201939093526002909101549091169181019190915290565b6007547f0000000000000000000000000000000000000000000000000000000000000000600160281b90910464ffffffffff16106105c85760405163b984588b60e01b815260040160405180910390fd5b6105da83600001518460200151610e6a565b6105f7576040516379fae7af60e01b815260040160405180910390fd5b60405163125c7dfb60e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906324b8fbf6906106459033908690600401612358565b600060405180830381600087803b15801561065f57600080fd5b505af1158015610673573d6000803e3d6000fd5b505060405163b36543a960e01b8152600092506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016915063b36543a9906106c89033908690600401612358565b602060405180830381865afa1580156106e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610709919061239a565b905060004290506000610735604051806060016040528088815260200185815260200184815250610c29565b9050610742600782610f14565b602086015186516007547fd3c3cd829e4e37d5baaf10abace26b24e0046e20500c999380410f807edfcda09061078890600190600160281b900464ffffffffff166123c9565b6040805164ffffffffff909216825260208201889052810186905260600160405180910390a3505050505050565b60405163248f667760e01b815260009073b8bc2c7cf71441ff7e6f111d3457e3d61c5649689063248f6677906107f09085906004016123ee565b602060405180830381865af415801561080d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610831919061239a565b92915050565b60006108436007611064565b905090565b60006000805160206126ff83398151915260028360405160200161086c919061241f565b60408051601f198184030181529082905261088691612455565b602060405180830381855afa1580156108a3573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906108c6919061239a565b6108319190612487565b60006108da611c1a565b838152602081018390526108ed816108f5565b949350505050565b6040516314d2f97b60e11b8152600090732f1398ab5e322d357df8cdd2e7ba73122c5fdda4906329a5f2f6906107f09085906004016124bf565b60058054600181019091558451602086015161094b9190610e6a565b610968576040516379fae7af60e01b815260040160405180910390fd5b606086015160ff1660006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166370f7b3618a8a8a30866109b160018a6124e7565b600581106109c1576109c16124a9565b01546040518663ffffffff1660e01b81526004016109e39594939291906124fa565b6020604051808303816000875af1158015610a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a26919061256b565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166336344873888885338a6040518663ffffffff1660e01b8152600401610a7e9594939291906125aa565b6020604051808303816000875af1158015610a9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac1919061256b565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663431a717589898686338c6040518763ffffffff1660e01b8152600401610b1b969594939291906125e9565b6020604051808303816000875af1158015610b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5e919061256b565b604080516060810182526001600160a01b038087168252858116602080840191825282861684860190815260008c815260068352869020855181549086166001600160a01b03199182161782559351600182018054918716918616919091179055905160029091018054919094169216919091179091558c01518c51925193945090929091907f38b2d18bb65cc91d7b436014cf44c8298b13bee60cc18d9e8efec26d1df3189090610c13908a908c90612631565b60405180910390a3505050505050505050505050565b6000610c33611c38565b8251518152825160209081015181830152830151816002602002015260408301516060820152610c62816107b6565b9392505050565b6000610c73611c56565b8351518152835160209081015190820152835160409081015190820152835160609081015190820152835160809081015190820152610cb0611c56565b845160a001518152845160c001516020820152845160e00151604080830191909152855161010001516060830152855161012001516080808401919091528151908101909152610d2e9080610d0485610d37565b8152602001610d1284610d37565b81526020018660000151815260200186602001518152506107b6565b95945050505050565b604051630926f44b60e31b81526000907337282fede56aa1d7266ecb12dc3b342d12044e2e90634937a258906107f0908590600401612645565b60008160058110610d8157600080fd5b0154905081565b6040516304b98e1d60e31b8152600090738778da47ef619f56341fe95514e95fa0ff3b77c6906325cc70e8906107f090859060040161266d565b610dca611c74565b60408051808201909152600080825260208201526000610de8611c8c565b84518152602080860151828201526040805180820182527f171e826ad4a870fd925e0bf0e87884e70e080879c2205ef10114f28a3b6f6dd781527f2bd407d897fbbca9f88adfd2d15252e69de8c1564eb4d3d27162e259172f1a1d8184015281519283019091528282529094509250610e618484610c69565b93959294505050565b6000806000805160206126ff833981519152848509905060006000805160206126ff833981519152848509905060006000805160206126ff833981519152826000805160206126ff83398151915285620292fc0908905060006000805160206126ff83398151915280846000805160206126ff83398151915287620292f809096001089050610f0882826000805160206126ff8339815191526110b4565b15979650505050505050565b8154600160281b900464ffffffffff16610f2f816001612695565b835464ffffffffff91909116600160281b0269ffffffffff0000000000199091161783558160005b81856001016000610f6884876110ef565b64ffffffffff168152602081019190915260400160002055600183161561105d576000610f9f82610f9a6001876123c9565b6110ef565b60408051808201825264ffffffffff8316600090815260018a01602090815290839020548252810186905290516314d2f97b60e11b8152919250732f1398ab5e322d357df8cdd2e7ba73122c5fdda4916329a5f2f691611001916004016124bf565b602060405180830381865af415801561101e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611042919061239a565b647fffffffff600195861c1694909350919091019050610f57565b5050505050565b8054600090600160281b900464ffffffffff1660015b8164ffffffffff168160ff166001901b64ffffffffff1610156110a957806110a1816126b3565b91505061107a565b6108ed848383611114565b6000838381116110cb576110c883826126d2565b90505b82806110d9576110d9612471565b60006110e586846124e7565b0895945050505050565b60008161110a60ff851664ff00000000602087901b166123c9565b610c629190612695565b600060208260ff16111561113b57604051633e104c7760e01b815260040160405180910390fd5b8264ffffffffff1660000361115a57611153826111e0565b9050610c62565b60006111678360016126e5565b60ff166001600160401b0381111561118157611181611cc4565b6040519080825280602002602001820160405280156111aa578160200160208202803683370190505b5090506111b98585858461186d565b808360ff16815181106111ce576111ce6124a9565b60200260200101519150509392505050565b60008160ff1660000361121457507f0ef71f46e11a513c599eed9dd03576c33439bcfb1cee155316f90541e41649ba919050565b8160ff1660010361124657507f06928e817d2804a3713efd102bae900c9ab3e8e0b0c6c20f8613bd3b0423a891919050565b8160ff1660020361127857507f2a06fb0b739b402c34dc752d8417b9cd67b7f7cabe4b06b5d995053791fcede4919050565b8160ff166003036112aa57507f04265868d2e705f48d3ae49f7749e67a587dafdb569c1d7334675496046eaad6919050565b8160ff166004036112dc57507f08e4b5d410c8de929132c214ea600b5f252fa14aabb97ea67cda5bb4e0ebeec8919050565b8160ff1660050361130e57507f11dc55d21b17daf8e60253c2a43d519039ba968733cf7c9d5df6155939e1a6d8919050565b8160ff1660060361134057507f30553f8216db90854953edd47602897f897104d5b0d65a5ce000981c51da32e0919050565b8160ff1660070361137257507f0690bfb582c7502ff6d15d519740ecd73d652b7a14dc82bfd250613ee8e04076919050565b8160ff166008036113a457507f1ea63a974336db6c0423e719d3f0e11494266237dda3a40de3cb761044366359919050565b8160ff166009036113d657507f1e73f08f6e5e4bb9c2096cc4587526ebfd033c222f4a27e97119c867c36a0d3a919050565b8160ff16600a0361140857507f10f7b76489e9c36644736c33c600d1bcedd465fd0aff3027e67b02e13875272d919050565b8160ff16600b0361143a57507f05e0136534f74776d69646bd0bd94519e63af45734405f479382d8400514c1a6919050565b8160ff16600c0361146c57507f1f336d6d45d293180c75964e99a7599d44cac2ad447c202c3e1973b0322cf990919050565b8160ff16600d0361149e57507f2582b5cdefe032d75373f0ede9171406137e93e7d44405a0b0a409c1c7391380919050565b8160ff16600e036114d057507f2ec047dd616221873c234f36461080c3e760644bb519ebdb49eb9645215e0edc919050565b8160ff16600f0361150257507f128fb9ad5b2d8e694bec0888ff95609c15b2a96ae80a34946c953dc503e46fb6919050565b8160ff1660100361153457507f199cd1f5b757c285023767abbe9bbb318da4e1fd375b5a001b54a0f3901ea7d3919050565b8160ff1660110361156657507f2b8342160822355808db759147a7d6f61de451bd5bb88f9db2eb406ea68b8138919050565b8160ff1660120361159857507f1874217e8e1dbc51c571a2db1103bf47c3e66a59305ca48bbcee6ad1c8cc5751919050565b8160ff166013036115ca57507f2c849a73ab21c9e88e1d711f221863e2a94eb58f3eb42dde575301451f3ec5c8919050565b8160ff166014036115fc57507f1713f3e3dc5e2393bd31ccc0cdd8601bdee3198cf34d566bb60cfab13e5a0873919050565b8160ff1660150361162e57507f2ce2c1fb109ad6574570826774ecfca3e04866bb5a3963962b873646db6641f3919050565b8160ff1660160361166057507f2560496c1138c827f1efb407d0cdb9d6ec9539b0957dfb67de2776e6026d630f919050565b8160ff1660170361169257507f1d71ada9e49baeb4a2cf26be37d3bc680554995ef6706105e93978ba71cacf94919050565b8160ff166018036116c457507f19b336a1e0a933e2a8f97d97322dcee843a2d9a2401bece52a3a25ddd5bb6bc9919050565b8160ff166019036116f657507f1b6367322bac9f24889900d310e2feaa0021516fac77470aea078e89335d3fcf919050565b8160ff16601a0361172857507f24cb019b59431c232413f66b041923214f7a8a7489caa05b66860f1c3c76d3b1919050565b8160ff16601b0361175a57507f132e4ff3e4ba890f1610efd4d2f69700b825514d557b82663878a56e2acef41c919050565b8160ff16601c0361178c57507f0845dd838ca63b2f68775aac8513bd692d26f511698206f3c6ce2b4100dd8d8f919050565b8160ff16601d036117be57507f14b46e659dc4072fc64a18d44911c4a303b45f1296c3cb7dec77f269bee9b5df919050565b8160ff16601e036117f057507f2b59c2651b412c029efa38f835ac1b1b5bdaf89dcb2e4bc9219e7d77c65e776a919050565b8160ff16601f0361182257507f216b9fa3ac3724cf1ec6caf5a66dd85cae3aee727e00d2a0a59f273df3401f10919050565b8160ff1660200361185457507f1d90601a0c76d2f39824f6dc198fb3b48cbd0231516c8f6208e56ea741c341f9919050565b6040516310a2ea0560e21b815260040160405180910390fd5b60208260ff16111561189257604051633e104c7760e01b815260040160405180910390fd5b8264ffffffffff166000036118ba5760405163bb5e95dd60e01b815260040160405180910390fd5b60006118c76001856123c9565b90506001811660000361191f578460010160006118e56000846110ef565b64ffffffffff168152602001908152602001600020548260008151811061190e5761190e6124a9565b602002602001018181525050611949565b61192960006111e0565b8260008151811061193c5761193c6124a9565b6020026020010181815250505b60005b8360ff168160ff161015611c125760018216600003611a4557732f1398ab5e322d357df8cdd2e7ba73122c5fdda46329a5f2f66040518060400160405280868560ff168151811061199f5761199f6124a9565b602002602001015181526020016119b5856111e0565b8152506040518263ffffffff1660e01b81526004016119d491906124bf565b602060405180830381865af41580156119f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a15919061239a565b83611a218360016126e5565b60ff1681518110611a3457611a346124a9565b602002602001018181525050611bff565b6000611a528260016126e5565b60ff168664ffffffffff16901c64ffffffffff16905060018364ffffffffff16901c64ffffffffff16811115611af7576000876001016000611aab856001611a9a91906126e5565b60018864ffffffffff16901c6110ef565b64ffffffffff1681526020019081526020016000205490508085846001611ad291906126e5565b60ff1681518110611ae557611ae56124a9565b60200260200101818152505050611bfd565b6000876001016000611b1085600188610f9a91906123c9565b64ffffffffff168152602001908152602001600020549050732f1398ab5e322d357df8cdd2e7ba73122c5fdda46329a5f2f66040518060400160405280848152602001888760ff1681518110611b6857611b686124a9565b60200260200101518152506040518263ffffffff1660e01b8152600401611b8f91906124bf565b602060405180830381865af4158015611bac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd0919061239a565b85611bdc8560016126e5565b60ff1681518110611bef57611bef6124a9565b602002602001018181525050505b505b647fffffffff600192831c16910161194c565b505050505050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b6040518060200160405280611c87611c8c565b905290565b604051806101400160405280600a906020820280368337509192915050565b600060208284031215611cbd57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b0381118282101715611cfd57611cfd611cc4565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611d2b57611d2b611cc4565b604052919050565b600060408284031215611d4557600080fd5b604051604081018181106001600160401b0382111715611d6757611d67611cc4565b604052823581526020928301359281019290925250919050565b600082601f830112611d9257600080fd5b81356001600160401b03811115611dab57611dab611cc4565b611dbe601f8201601f1916602001611d03565b818152846020838601011115611dd357600080fd5b816020850160208301376000918101602001919091529392505050565b600080600060808486031215611e0557600080fd5b611e0f8585611d33565b925060408401356001600160401b0380821115611e2b57600080fd5b611e3787838801611d81565b93506060860135915080821115611e4d57600080fd5b50611e5a86828701611d81565b9150509250925092565b600060808284031215611e7657600080fd5b82601f830112611e8557600080fd5b604051608081018181106001600160401b0382111715611ea757611ea7611cc4565b604052806080840185811115611ebc57600080fd5b845b81811015611ed6578035835260209283019201611ebe565b509195945050505050565b60006020808385031215611ef457600080fd5b82356001600160401b0380821115611f0b57600080fd5b818501915085601f830112611f1f57600080fd5b813581811115611f3157611f31611cc4565b8060051b9150611f42848301611d03565b8181529183018401918481019088841115611f5c57600080fd5b938501935b83851015611f7a57843582529385019390850190611f61565b98975050505050505050565b60008060408385031215611f9957600080fd5b50508035926020909101359150565b600060408284031215611fba57600080fd5b82601f830112611fc957600080fd5b604051604081018181106001600160401b0382111715611feb57611feb611cc4565b8060405250806040840185811115611ebc57600080fd5b803560ff8116811461201357600080fd5b919050565b6001600160a01b038116811461202d57600080fd5b50565b803561201381612018565b80356002811061201357600080fd5b60008060008060008086880361014081121561206557600080fd5b873596506080601f198201121561207b57600080fd5b50604051608081018181106001600160401b038211171561209e5761209e611cc4565b6040526120ad60208901612002565b81526120bb60408901612002565b60208201526120cc60608901612002565b60408201526120dd60808901612002565b606082015294506120f18860a08901611d33565b93506120ff60e08801612030565b925061210e6101008801612030565b915061211d610120880161203b565b90509295509295509295565b60006080828403121561213b57600080fd5b604051606081018181106001600160401b038211171561215d5761215d611cc4565b60405261216a8484611d33565b815260408301356020820152606083013560408201528091505092915050565b60008082840361018081121561219f57600080fd5b610140808212156121af57600080fd5b604051915060208083018381106001600160401b03821117156121d4576121d4611cc4565b604052601f860187136121e657600080fd5b6121ee611cda565b91860191808884111561220057600080fd5b875b848110156122195780358352918301918301612202565b5080855250505081935061222d8682611d33565b925050509250929050565b600060a0828403121561224a57600080fd5b82601f83011261225957600080fd5b60405160a081018181106001600160401b038211171561227b5761227b611cc4565b6040528060a0840185811115611ebc57600080fd5b6000606082840312156122a257600080fd5b82601f8301126122b157600080fd5b604051606081018181106001600160401b03821117156122d3576122d3611cc4565b604052806060840185811115611ebc57600080fd5b83516101a08201908260005b600a8110156123135782518252602092830192909101906001016122f4565b50508451610140840152506020909301516101608201526101800152919050565b60005b8381101561234f578181015183820152602001612337565b50506000910152565b60018060a01b03831681526040602082015260008251806040840152612385816060850160208701612334565b601f01601f1916919091016060019392505050565b6000602082840312156123ac57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff8281168282160390808211156123e7576123e76123b3565b5092915050565b60808101818360005b60048110156124165781518352602092830192909101906001016123f7565b50505092915050565b815160009082906020808601845b838110156124495781518552938201939082019060010161242d565b50929695505050505050565b60008251612467818460208701612334565b9190910192915050565b634e487b7160e01b600052601260045260246000fd5b6000826124a457634e487b7160e01b600052601260045260246000fd5b500690565b634e487b7160e01b600052603260045260246000fd5b60408101818360005b60028110156124165781518352602092830192909101906001016124c8565b81810381811115610831576108316123b3565b60006101208201905086825260ff865116602083015260ff602087015116604083015260ff604087015116606083015260ff606087015116608083015261254e60a083018680518252602090810151910152565b6001600160a01b039390931660e082015261010001529392505050565b60006020828403121561257d57600080fd5b8151610c6281612018565b600281106125a657634e487b7160e01b600052602160045260246000fd5b9052565b6001600160a01b038681168252858116602083015284811660408301528316606082015260a081016125df6080830184612588565b9695505050505050565b6001600160a01b0387811682528681166020830152858116604083015284811660608301528316608082015260c0810161262660a0830184612588565b979650505050505050565b82815260408101610c626020830184612588565b60a08101818360005b600581101561241657815183526020928301929091019060010161264e565b60608101818360005b6003811015612416578151835260209283019290910190600101612676565b64ffffffffff8181168382160190808211156123e7576123e76123b3565b600060ff821660ff81036126c9576126c96123b3565b60010192915050565b80820180821115610831576108316123b3565b60ff8181168382160190811115610831576108316123b356fe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a2646970667358221220cd6cb498a0a85d0e5e5af107d53349e78c14508c00eabc21b88f5a675db1719564736f6c634300081400330000000000000000000000002f1a5b4f8f3b7348c66a1522622b1db712261607000000000000000000000000e4c9d4248f1371c5c61d406a9859f9fe667567a500000000000000000000000057034389dbe3de1d1c14763f55b77a2279d6d43c0000000000000000000000008ba83dd6e0e448417c519a38c90ee570a4ca3e9f00000000000000000000000016fc13edd59d4b9f788fb11a70ea022e1bb1b856000000000000000000000000000000000000000000000000000000000000000e16ca9c2bd2749e2dd5fc4dc4b16eeb69725f2113a0b249c31888faedb50a7a522293366da9ebd5b18f76d315dcbb63ade498fd5fbc4ec3ad005a187d4c91beee065ed83b3b1abc7fa95ca782ff87b08ae9323e93bc85b9deaa4d21ecd73705bb1b9f569ce964472843bf971c2d4101670189d831fbcd56a12c5126422433e24b0181dd75786c1f23e10c5e76fb533559576214fd1441f37e3c0bfb4cd726ce5d
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061018e5760003560e01c8063652c76e4116100de578063aab4a67011610097578063b87802c811610071578063b87802c814610477578063bea140b31461048a578063df82635a1461049d578063edbfe83f146104c457600080fd5b8063aab4a670146103b0578063ac2f0074146103d7578063b68687201461043d57600080fd5b8063652c76e414610323578063683f3dc31461035c5780636b4575e2146103645780637d0a81c8146103775780638a2a3dfb1461038a5780639cfced971461039d57600080fd5b8063343393b51161014b57806358bfc3791161012557806358bfc379146102c35780635bb93995146102d657806362a361bb146102e957806362b31f1e146102fc57600080fd5b8063343393b5146102815780633dfb88b2146102a8578063423f3e19146102bb57600080fd5b8063055575eb14610193578063079410db146101d7578063122db153146101fe5780631a8cbcaa1461021e5780632b786571146102635780633364120a1461026c575b600080fd5b6101ba7f000000000000000000000000e4c9d4248f1371c5c61d406a9859f9fe667567a581565b6040516001600160a01b0390911681526020015b60405180910390f35b6101ba7f0000000000000000000000008ba83dd6e0e448417c519a38c90ee570a4ca3e9f81565b600754600160281b900464ffffffffff165b6040519081526020016101ce565b61023161022c366004611cab565b6104e6565b6040805182516001600160a01b03908116825260208085015182169083015292820151909216908201526060016101ce565b61021060055481565b61027f61027a366004611df0565b610577565b005b6101ba7f0000000000000000000000002f1a5b4f8f3b7348c66a1522622b1db71226160781565b6102106102b6366004611e64565b6107b6565b610210610837565b6102106102d1366004611ee1565b610848565b6102106102e4366004611f86565b6108d0565b6102106102f7366004611fa8565b6108f5565b6101ba7f00000000000000000000000057034389dbe3de1d1c14763f55b77a2279d6d43c81565b61034a7f000000000000000000000000000000000000000000000000000000000000000e81565b60405160ff90911681526020016101ce565b61034a600a81565b61027f61037236600461204a565b61092f565b610210610385366004612129565b610c29565b61021061039836600461218a565b610c69565b6102106103ab366004612238565b610d37565b6101ba7f00000000000000000000000016fc13edd59d4b9f788fb11a70ea022e1bb1b85681565b6104136103e5366004611cab565b6006602052600090815260409020805460018201546002909201546001600160a01b03918216928216911683565b604080516001600160a01b03948516815292841660208401529216918101919091526060016101ce565b6007546104599064ffffffffff80821691600160281b90041682565b6040805164ffffffffff9384168152929091166020830152016101ce565b610210610485366004611cab565b610d71565b610210610498366004612290565b610d88565b6102107f000000000000000000000000000000000000000000000000000000000000400081565b6104d76104d2366004611fa8565b610dc2565b6040516101ce939291906122e8565b6040805160608101825260008082526020820181905291810191909152600554821061052c5760405163a86ecdd560e01b81526004810183905260240160405180910390fd5b50600090815260066020908152604091829020825160608101845281546001600160a01b03908116825260018301548116938201939093526002909101549091169181019190915290565b6007547f0000000000000000000000000000000000000000000000000000000000004000600160281b90910464ffffffffff16106105c85760405163b984588b60e01b815260040160405180910390fd5b6105da83600001518460200151610e6a565b6105f7576040516379fae7af60e01b815260040160405180910390fd5b60405163125c7dfb60e11b81526001600160a01b037f0000000000000000000000008ba83dd6e0e448417c519a38c90ee570a4ca3e9f16906324b8fbf6906106459033908690600401612358565b600060405180830381600087803b15801561065f57600080fd5b505af1158015610673573d6000803e3d6000fd5b505060405163b36543a960e01b8152600092506001600160a01b037f00000000000000000000000016fc13edd59d4b9f788fb11a70ea022e1bb1b85616915063b36543a9906106c89033908690600401612358565b602060405180830381865afa1580156106e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610709919061239a565b905060004290506000610735604051806060016040528088815260200185815260200184815250610c29565b9050610742600782610f14565b602086015186516007547fd3c3cd829e4e37d5baaf10abace26b24e0046e20500c999380410f807edfcda09061078890600190600160281b900464ffffffffff166123c9565b6040805164ffffffffff909216825260208201889052810186905260600160405180910390a3505050505050565b60405163248f667760e01b815260009073b8bc2c7cf71441ff7e6f111d3457e3d61c5649689063248f6677906107f09085906004016123ee565b602060405180830381865af415801561080d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610831919061239a565b92915050565b60006108436007611064565b905090565b60006000805160206126ff83398151915260028360405160200161086c919061241f565b60408051601f198184030181529082905261088691612455565b602060405180830381855afa1580156108a3573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906108c6919061239a565b6108319190612487565b60006108da611c1a565b838152602081018390526108ed816108f5565b949350505050565b6040516314d2f97b60e11b8152600090732f1398ab5e322d357df8cdd2e7ba73122c5fdda4906329a5f2f6906107f09085906004016124bf565b60058054600181019091558451602086015161094b9190610e6a565b610968576040516379fae7af60e01b815260040160405180910390fd5b606086015160ff1660006001600160a01b037f0000000000000000000000002f1a5b4f8f3b7348c66a1522622b1db712261607166370f7b3618a8a8a30866109b160018a6124e7565b600581106109c1576109c16124a9565b01546040518663ffffffff1660e01b81526004016109e39594939291906124fa565b6020604051808303816000875af1158015610a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a26919061256b565b905060007f000000000000000000000000e4c9d4248f1371c5c61d406a9859f9fe667567a56001600160a01b03166336344873888885338a6040518663ffffffff1660e01b8152600401610a7e9594939291906125aa565b6020604051808303816000875af1158015610a9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac1919061256b565b905060007f00000000000000000000000057034389dbe3de1d1c14763f55b77a2279d6d43c6001600160a01b031663431a717589898686338c6040518763ffffffff1660e01b8152600401610b1b969594939291906125e9565b6020604051808303816000875af1158015610b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5e919061256b565b604080516060810182526001600160a01b038087168252858116602080840191825282861684860190815260008c815260068352869020855181549086166001600160a01b03199182161782559351600182018054918716918616919091179055905160029091018054919094169216919091179091558c01518c51925193945090929091907f38b2d18bb65cc91d7b436014cf44c8298b13bee60cc18d9e8efec26d1df3189090610c13908a908c90612631565b60405180910390a3505050505050505050505050565b6000610c33611c38565b8251518152825160209081015181830152830151816002602002015260408301516060820152610c62816107b6565b9392505050565b6000610c73611c56565b8351518152835160209081015190820152835160409081015190820152835160609081015190820152835160809081015190820152610cb0611c56565b845160a001518152845160c001516020820152845160e00151604080830191909152855161010001516060830152855161012001516080808401919091528151908101909152610d2e9080610d0485610d37565b8152602001610d1284610d37565b81526020018660000151815260200186602001518152506107b6565b95945050505050565b604051630926f44b60e31b81526000907337282fede56aa1d7266ecb12dc3b342d12044e2e90634937a258906107f0908590600401612645565b60008160058110610d8157600080fd5b0154905081565b6040516304b98e1d60e31b8152600090738778da47ef619f56341fe95514e95fa0ff3b77c6906325cc70e8906107f090859060040161266d565b610dca611c74565b60408051808201909152600080825260208201526000610de8611c8c565b84518152602080860151828201526040805180820182527f171e826ad4a870fd925e0bf0e87884e70e080879c2205ef10114f28a3b6f6dd781527f2bd407d897fbbca9f88adfd2d15252e69de8c1564eb4d3d27162e259172f1a1d8184015281519283019091528282529094509250610e618484610c69565b93959294505050565b6000806000805160206126ff833981519152848509905060006000805160206126ff833981519152848509905060006000805160206126ff833981519152826000805160206126ff83398151915285620292fc0908905060006000805160206126ff83398151915280846000805160206126ff83398151915287620292f809096001089050610f0882826000805160206126ff8339815191526110b4565b15979650505050505050565b8154600160281b900464ffffffffff16610f2f816001612695565b835464ffffffffff91909116600160281b0269ffffffffff0000000000199091161783558160005b81856001016000610f6884876110ef565b64ffffffffff168152602081019190915260400160002055600183161561105d576000610f9f82610f9a6001876123c9565b6110ef565b60408051808201825264ffffffffff8316600090815260018a01602090815290839020548252810186905290516314d2f97b60e11b8152919250732f1398ab5e322d357df8cdd2e7ba73122c5fdda4916329a5f2f691611001916004016124bf565b602060405180830381865af415801561101e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611042919061239a565b647fffffffff600195861c1694909350919091019050610f57565b5050505050565b8054600090600160281b900464ffffffffff1660015b8164ffffffffff168160ff166001901b64ffffffffff1610156110a957806110a1816126b3565b91505061107a565b6108ed848383611114565b6000838381116110cb576110c883826126d2565b90505b82806110d9576110d9612471565b60006110e586846124e7565b0895945050505050565b60008161110a60ff851664ff00000000602087901b166123c9565b610c629190612695565b600060208260ff16111561113b57604051633e104c7760e01b815260040160405180910390fd5b8264ffffffffff1660000361115a57611153826111e0565b9050610c62565b60006111678360016126e5565b60ff166001600160401b0381111561118157611181611cc4565b6040519080825280602002602001820160405280156111aa578160200160208202803683370190505b5090506111b98585858461186d565b808360ff16815181106111ce576111ce6124a9565b60200260200101519150509392505050565b60008160ff1660000361121457507f0ef71f46e11a513c599eed9dd03576c33439bcfb1cee155316f90541e41649ba919050565b8160ff1660010361124657507f06928e817d2804a3713efd102bae900c9ab3e8e0b0c6c20f8613bd3b0423a891919050565b8160ff1660020361127857507f2a06fb0b739b402c34dc752d8417b9cd67b7f7cabe4b06b5d995053791fcede4919050565b8160ff166003036112aa57507f04265868d2e705f48d3ae49f7749e67a587dafdb569c1d7334675496046eaad6919050565b8160ff166004036112dc57507f08e4b5d410c8de929132c214ea600b5f252fa14aabb97ea67cda5bb4e0ebeec8919050565b8160ff1660050361130e57507f11dc55d21b17daf8e60253c2a43d519039ba968733cf7c9d5df6155939e1a6d8919050565b8160ff1660060361134057507f30553f8216db90854953edd47602897f897104d5b0d65a5ce000981c51da32e0919050565b8160ff1660070361137257507f0690bfb582c7502ff6d15d519740ecd73d652b7a14dc82bfd250613ee8e04076919050565b8160ff166008036113a457507f1ea63a974336db6c0423e719d3f0e11494266237dda3a40de3cb761044366359919050565b8160ff166009036113d657507f1e73f08f6e5e4bb9c2096cc4587526ebfd033c222f4a27e97119c867c36a0d3a919050565b8160ff16600a0361140857507f10f7b76489e9c36644736c33c600d1bcedd465fd0aff3027e67b02e13875272d919050565b8160ff16600b0361143a57507f05e0136534f74776d69646bd0bd94519e63af45734405f479382d8400514c1a6919050565b8160ff16600c0361146c57507f1f336d6d45d293180c75964e99a7599d44cac2ad447c202c3e1973b0322cf990919050565b8160ff16600d0361149e57507f2582b5cdefe032d75373f0ede9171406137e93e7d44405a0b0a409c1c7391380919050565b8160ff16600e036114d057507f2ec047dd616221873c234f36461080c3e760644bb519ebdb49eb9645215e0edc919050565b8160ff16600f0361150257507f128fb9ad5b2d8e694bec0888ff95609c15b2a96ae80a34946c953dc503e46fb6919050565b8160ff1660100361153457507f199cd1f5b757c285023767abbe9bbb318da4e1fd375b5a001b54a0f3901ea7d3919050565b8160ff1660110361156657507f2b8342160822355808db759147a7d6f61de451bd5bb88f9db2eb406ea68b8138919050565b8160ff1660120361159857507f1874217e8e1dbc51c571a2db1103bf47c3e66a59305ca48bbcee6ad1c8cc5751919050565b8160ff166013036115ca57507f2c849a73ab21c9e88e1d711f221863e2a94eb58f3eb42dde575301451f3ec5c8919050565b8160ff166014036115fc57507f1713f3e3dc5e2393bd31ccc0cdd8601bdee3198cf34d566bb60cfab13e5a0873919050565b8160ff1660150361162e57507f2ce2c1fb109ad6574570826774ecfca3e04866bb5a3963962b873646db6641f3919050565b8160ff1660160361166057507f2560496c1138c827f1efb407d0cdb9d6ec9539b0957dfb67de2776e6026d630f919050565b8160ff1660170361169257507f1d71ada9e49baeb4a2cf26be37d3bc680554995ef6706105e93978ba71cacf94919050565b8160ff166018036116c457507f19b336a1e0a933e2a8f97d97322dcee843a2d9a2401bece52a3a25ddd5bb6bc9919050565b8160ff166019036116f657507f1b6367322bac9f24889900d310e2feaa0021516fac77470aea078e89335d3fcf919050565b8160ff16601a0361172857507f24cb019b59431c232413f66b041923214f7a8a7489caa05b66860f1c3c76d3b1919050565b8160ff16601b0361175a57507f132e4ff3e4ba890f1610efd4d2f69700b825514d557b82663878a56e2acef41c919050565b8160ff16601c0361178c57507f0845dd838ca63b2f68775aac8513bd692d26f511698206f3c6ce2b4100dd8d8f919050565b8160ff16601d036117be57507f14b46e659dc4072fc64a18d44911c4a303b45f1296c3cb7dec77f269bee9b5df919050565b8160ff16601e036117f057507f2b59c2651b412c029efa38f835ac1b1b5bdaf89dcb2e4bc9219e7d77c65e776a919050565b8160ff16601f0361182257507f216b9fa3ac3724cf1ec6caf5a66dd85cae3aee727e00d2a0a59f273df3401f10919050565b8160ff1660200361185457507f1d90601a0c76d2f39824f6dc198fb3b48cbd0231516c8f6208e56ea741c341f9919050565b6040516310a2ea0560e21b815260040160405180910390fd5b60208260ff16111561189257604051633e104c7760e01b815260040160405180910390fd5b8264ffffffffff166000036118ba5760405163bb5e95dd60e01b815260040160405180910390fd5b60006118c76001856123c9565b90506001811660000361191f578460010160006118e56000846110ef565b64ffffffffff168152602001908152602001600020548260008151811061190e5761190e6124a9565b602002602001018181525050611949565b61192960006111e0565b8260008151811061193c5761193c6124a9565b6020026020010181815250505b60005b8360ff168160ff161015611c125760018216600003611a4557732f1398ab5e322d357df8cdd2e7ba73122c5fdda46329a5f2f66040518060400160405280868560ff168151811061199f5761199f6124a9565b602002602001015181526020016119b5856111e0565b8152506040518263ffffffff1660e01b81526004016119d491906124bf565b602060405180830381865af41580156119f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a15919061239a565b83611a218360016126e5565b60ff1681518110611a3457611a346124a9565b602002602001018181525050611bff565b6000611a528260016126e5565b60ff168664ffffffffff16901c64ffffffffff16905060018364ffffffffff16901c64ffffffffff16811115611af7576000876001016000611aab856001611a9a91906126e5565b60018864ffffffffff16901c6110ef565b64ffffffffff1681526020019081526020016000205490508085846001611ad291906126e5565b60ff1681518110611ae557611ae56124a9565b60200260200101818152505050611bfd565b6000876001016000611b1085600188610f9a91906123c9565b64ffffffffff168152602001908152602001600020549050732f1398ab5e322d357df8cdd2e7ba73122c5fdda46329a5f2f66040518060400160405280848152602001888760ff1681518110611b6857611b686124a9565b60200260200101518152506040518263ffffffff1660e01b8152600401611b8f91906124bf565b602060405180830381865af4158015611bac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd0919061239a565b85611bdc8560016126e5565b60ff1681518110611bef57611bef6124a9565b602002602001018181525050505b505b647fffffffff600192831c16910161194c565b505050505050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b6040518060200160405280611c87611c8c565b905290565b604051806101400160405280600a906020820280368337509192915050565b600060208284031215611cbd57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b0381118282101715611cfd57611cfd611cc4565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611d2b57611d2b611cc4565b604052919050565b600060408284031215611d4557600080fd5b604051604081018181106001600160401b0382111715611d6757611d67611cc4565b604052823581526020928301359281019290925250919050565b600082601f830112611d9257600080fd5b81356001600160401b03811115611dab57611dab611cc4565b611dbe601f8201601f1916602001611d03565b818152846020838601011115611dd357600080fd5b816020850160208301376000918101602001919091529392505050565b600080600060808486031215611e0557600080fd5b611e0f8585611d33565b925060408401356001600160401b0380821115611e2b57600080fd5b611e3787838801611d81565b93506060860135915080821115611e4d57600080fd5b50611e5a86828701611d81565b9150509250925092565b600060808284031215611e7657600080fd5b82601f830112611e8557600080fd5b604051608081018181106001600160401b0382111715611ea757611ea7611cc4565b604052806080840185811115611ebc57600080fd5b845b81811015611ed6578035835260209283019201611ebe565b509195945050505050565b60006020808385031215611ef457600080fd5b82356001600160401b0380821115611f0b57600080fd5b818501915085601f830112611f1f57600080fd5b813581811115611f3157611f31611cc4565b8060051b9150611f42848301611d03565b8181529183018401918481019088841115611f5c57600080fd5b938501935b83851015611f7a57843582529385019390850190611f61565b98975050505050505050565b60008060408385031215611f9957600080fd5b50508035926020909101359150565b600060408284031215611fba57600080fd5b82601f830112611fc957600080fd5b604051604081018181106001600160401b0382111715611feb57611feb611cc4565b8060405250806040840185811115611ebc57600080fd5b803560ff8116811461201357600080fd5b919050565b6001600160a01b038116811461202d57600080fd5b50565b803561201381612018565b80356002811061201357600080fd5b60008060008060008086880361014081121561206557600080fd5b873596506080601f198201121561207b57600080fd5b50604051608081018181106001600160401b038211171561209e5761209e611cc4565b6040526120ad60208901612002565b81526120bb60408901612002565b60208201526120cc60608901612002565b60408201526120dd60808901612002565b606082015294506120f18860a08901611d33565b93506120ff60e08801612030565b925061210e6101008801612030565b915061211d610120880161203b565b90509295509295509295565b60006080828403121561213b57600080fd5b604051606081018181106001600160401b038211171561215d5761215d611cc4565b60405261216a8484611d33565b815260408301356020820152606083013560408201528091505092915050565b60008082840361018081121561219f57600080fd5b610140808212156121af57600080fd5b604051915060208083018381106001600160401b03821117156121d4576121d4611cc4565b604052601f860187136121e657600080fd5b6121ee611cda565b91860191808884111561220057600080fd5b875b848110156122195780358352918301918301612202565b5080855250505081935061222d8682611d33565b925050509250929050565b600060a0828403121561224a57600080fd5b82601f83011261225957600080fd5b60405160a081018181106001600160401b038211171561227b5761227b611cc4565b6040528060a0840185811115611ebc57600080fd5b6000606082840312156122a257600080fd5b82601f8301126122b157600080fd5b604051606081018181106001600160401b03821117156122d3576122d3611cc4565b604052806060840185811115611ebc57600080fd5b83516101a08201908260005b600a8110156123135782518252602092830192909101906001016122f4565b50508451610140840152506020909301516101608201526101800152919050565b60005b8381101561234f578181015183820152602001612337565b50506000910152565b60018060a01b03831681526040602082015260008251806040840152612385816060850160208701612334565b601f01601f1916919091016060019392505050565b6000602082840312156123ac57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff8281168282160390808211156123e7576123e76123b3565b5092915050565b60808101818360005b60048110156124165781518352602092830192909101906001016123f7565b50505092915050565b815160009082906020808601845b838110156124495781518552938201939082019060010161242d565b50929695505050505050565b60008251612467818460208701612334565b9190910192915050565b634e487b7160e01b600052601260045260246000fd5b6000826124a457634e487b7160e01b600052601260045260246000fd5b500690565b634e487b7160e01b600052603260045260246000fd5b60408101818360005b60028110156124165781518352602092830192909101906001016124c8565b81810381811115610831576108316123b3565b60006101208201905086825260ff865116602083015260ff602087015116604083015260ff604087015116606083015260ff606087015116608083015261254e60a083018680518252602090810151910152565b6001600160a01b039390931660e082015261010001529392505050565b60006020828403121561257d57600080fd5b8151610c6281612018565b600281106125a657634e487b7160e01b600052602160045260246000fd5b9052565b6001600160a01b038681168252858116602083015284811660408301528316606082015260a081016125df6080830184612588565b9695505050505050565b6001600160a01b0387811682528681166020830152858116604083015284811660608301528316608082015260c0810161262660a0830184612588565b979650505050505050565b82815260408101610c626020830184612588565b60a08101818360005b600581101561241657815183526020928301929091019060010161264e565b60608101818360005b6003811015612416578151835260209283019290910190600101612676565b64ffffffffff8181168382160190808211156123e7576123e76123b3565b600060ff821660ff81036126c9576126c96123b3565b60010192915050565b80820180821115610831576108316123b3565b60ff8181168382160190811115610831576108316123b356fe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a2646970667358221220cd6cb498a0a85d0e5e5af107d53349e78c14508c00eabc21b88f5a675db1719564736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002f1a5b4f8f3b7348c66a1522622b1db712261607000000000000000000000000e4c9d4248f1371c5c61d406a9859f9fe667567a500000000000000000000000057034389dbe3de1d1c14763f55b77a2279d6d43c0000000000000000000000008ba83dd6e0e448417c519a38c90ee570a4ca3e9f00000000000000000000000016fc13edd59d4b9f788fb11a70ea022e1bb1b856000000000000000000000000000000000000000000000000000000000000000e16ca9c2bd2749e2dd5fc4dc4b16eeb69725f2113a0b249c31888faedb50a7a522293366da9ebd5b18f76d315dcbb63ade498fd5fbc4ec3ad005a187d4c91beee065ed83b3b1abc7fa95ca782ff87b08ae9323e93bc85b9deaa4d21ecd73705bb1b9f569ce964472843bf971c2d4101670189d831fbcd56a12c5126422433e24b0181dd75786c1f23e10c5e76fb533559576214fd1441f37e3c0bfb4cd726ce5d
-----Decoded View---------------
Arg [0] : _pollFactory (address): 0x2F1A5B4F8F3B7348C66A1522622b1DB712261607
Arg [1] : _messageProcessorFactory (address): 0xE4c9d4248F1371C5C61d406A9859f9FE667567a5
Arg [2] : _tallyFactory (address): 0x57034389Dbe3DE1D1C14763f55B77A2279D6d43C
Arg [3] : _signUpGatekeeper (address): 0x8BA83Dd6E0E448417C519A38c90Ee570A4CA3e9f
Arg [4] : _initialVoiceCreditProxy (address): 0x16FC13edD59D4b9F788Fb11A70eA022E1Bb1B856
Arg [5] : _stateTreeDepth (uint8): 14
Arg [6] : _emptyBallotRoots (uint256[5]): 10308863629788455260704114511206948419734522911868369522065170317043305183826,15638739021185187188102975938431888963456846511635661527443326021687795891950,2881453089660950474651054122995901965405144719081991993059633221387893015995,12493973375564475576522276362572267105610392684775593820450263906986447069771,681764572878032401682084991233323592871239508639381808618717128728252960349
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000002f1a5b4f8f3b7348c66a1522622b1db712261607
Arg [1] : 000000000000000000000000e4c9d4248f1371c5c61d406a9859f9fe667567a5
Arg [2] : 00000000000000000000000057034389dbe3de1d1c14763f55b77a2279d6d43c
Arg [3] : 0000000000000000000000008ba83dd6e0e448417c519a38c90ee570a4ca3e9f
Arg [4] : 00000000000000000000000016fc13edd59d4b9f788fb11a70ea022e1bb1b856
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [6] : 16ca9c2bd2749e2dd5fc4dc4b16eeb69725f2113a0b249c31888faedb50a7a52
Arg [7] : 2293366da9ebd5b18f76d315dcbb63ade498fd5fbc4ec3ad005a187d4c91beee
Arg [8] : 065ed83b3b1abc7fa95ca782ff87b08ae9323e93bc85b9deaa4d21ecd73705bb
Arg [9] : 1b9f569ce964472843bf971c2d4101670189d831fbcd56a12c5126422433e24b
Arg [10] : 0181dd75786c1f23e10c5e76fb533559576214fd1441f37e3c0bfb4cd726ce5d
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.