Scroll Sepolia Testnet

Contract

0xdA10b22B81eb8EA6BC04aa9b86d3f9d969CD49F0

Overview

ETH Balance

Scroll Sepolia LogoScroll Sepolia LogoScroll Sepolia Logo0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
59557472024-08-06 9:11:17164 days ago1722935477
0xdA10b22B...969CD49F0
0 ETH
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xfcaFB222...dEbcCE72c
The constructor portion of the code might be different and could alter the actual behaviour of the contract

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)

File 1 of 21 : MACI.sol
// 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;
  }
}

File 2 of 21 : Ownable.sol
// 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);
    }
}

File 3 of 21 : Context.sol
// 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;
    }
}

File 4 of 21 : BabyJubJub.sol
// @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)
      }
    }
  }
}

File 5 of 21 : Hasher.sol
// 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);
  }
}

File 6 of 21 : PoseidonT3.sol
// 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) {}
}

File 7 of 21 : PoseidonT4.sol
// 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) {}
}

File 8 of 21 : PoseidonT5.sol
// 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) {}
}

File 9 of 21 : PoseidonT6.sol
// 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) {}
}

File 10 of 21 : SnarkConstants.sol
// 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;
}

File 11 of 21 : SignUpGatekeeper.sol
// 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);
}

File 12 of 21 : InitialVoiceCreditProxy.sol
// 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) {}
}

File 13 of 21 : IMACI.sol
// 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);
}

File 14 of 21 : IMPFactory.sol
// 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);
}

File 15 of 21 : IPollFactory.sol
// 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);
}

File 16 of 21 : ITallyFactory.sol
// 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);
}

File 17 of 21 : AccQueue.sol
// 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;
  }
}

File 18 of 21 : LazyIMT.sol
// 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++;
      }
    }
  }
}

File 19 of 21 : DomainObjs.sol
// 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;
  }
}

File 20 of 21 : Params.sol
// 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;
  }
}

File 21 of 21 : Utilities.sol
// 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]);
  }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {
    "contracts/crypto/PoseidonT3.sol": {
      "PoseidonT3": "0x88c2c6a7535463962a34757fe63cc4f296381aba"
    },
    "contracts/crypto/PoseidonT4.sol": {
      "PoseidonT4": "0xf8e637e5c9ec3a8d8fa8843a6df833348e1f1e66"
    },
    "contracts/crypto/PoseidonT5.sol": {
      "PoseidonT5": "0x0a0d66bafda8c8838281084d9c3d68dd9a6fc274"
    },
    "contracts/crypto/PoseidonT6.sol": {
      "PoseidonT6": "0xd2f6c828606ad8e985008cd825012f269b50cd58"
    }
  }
}

Contract ABI

[{"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"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061018e5760003560e01c8063652c76e4116100de578063aab4a67011610097578063b87802c811610071578063b87802c814610477578063bea140b31461048a578063df82635a1461049d578063edbfe83f146104c457600080fd5b8063aab4a670146103b0578063ac2f0074146103d7578063b68687201461043d57600080fd5b8063652c76e414610323578063683f3dc31461035c5780636b4575e2146103645780637d0a81c8146103775780638a2a3dfb1461038a5780639cfced971461039d57600080fd5b8063343393b51161014b57806358bfc3791161012557806358bfc379146102c35780635bb93995146102d657806362a361bb146102e957806362b31f1e146102fc57600080fd5b8063343393b5146102815780633dfb88b2146102a8578063423f3e19146102bb57600080fd5b8063055575eb14610193578063079410db146101d7578063122db153146101fe5780631a8cbcaa1461021e5780632b786571146102635780633364120a1461026c575b600080fd5b6101ba7f00000000000000000000000050045b05cb1c76410783d8a3e5625a99d572933981565b6040516001600160a01b0390911681526020015b60405180910390f35b6101ba7f00000000000000000000000083dd551541c580e338206f1f677835d427c92de281565b600754600160281b900464ffffffffff165b6040519081526020016101ce565b61023161022c366004611cab565b6104e6565b6040805182516001600160a01b03908116825260208085015182169083015292820151909216908201526060016101ce565b61021060055481565b61027f61027a366004611df0565b610577565b005b6101ba7f000000000000000000000000982530673ce9e5efa02438c694d48327aa4fb59281565b6102106102b6366004611e64565b6107b6565b610210610837565b6102106102d1366004611ee1565b610848565b6102106102e4366004611f86565b6108d0565b6102106102f7366004611fa8565b6108f5565b6101ba7f000000000000000000000000bb28555e989799478442483cd1f2d370a14e2c4281565b61034a7f000000000000000000000000000000000000000000000000000000000000000a81565b60405160ff90911681526020016101ce565b61034a600a81565b61027f61037236600461204a565b61092f565b610210610385366004612129565b610c29565b61021061039836600461218a565b610c69565b6102106103ab366004612238565b610d37565b6101ba7f000000000000000000000000b486cce9b4507a67db147b0802d5673774c8d27881565b6104136103e5366004611cab565b6006602052600090815260409020805460018201546002909201546001600160a01b03918216928216911683565b604080516001600160a01b03948516815292841660208401529216918101919091526060016101ce565b6007546104599064ffffffffff80821691600160281b90041682565b6040805164ffffffffff9384168152929091166020830152016101ce565b610210610485366004611cab565b610d71565b610210610498366004612290565b610d88565b6102107f000000000000000000000000000000000000000000000000000000000000040081565b6104d76104d2366004611fa8565b610dc2565b6040516101ce939291906122e8565b6040805160608101825260008082526020820181905291810191909152600554821061052c5760405163a86ecdd560e01b81526004810183905260240160405180910390fd5b50600090815260066020908152604091829020825160608101845281546001600160a01b03908116825260018301548116938201939093526002909101549091169181019190915290565b6007547f0000000000000000000000000000000000000000000000000000000000000400600160281b90910464ffffffffff16106105c85760405163b984588b60e01b815260040160405180910390fd5b6105da83600001518460200151610e6a565b6105f7576040516379fae7af60e01b815260040160405180910390fd5b60405163125c7dfb60e11b81526001600160a01b037f00000000000000000000000083dd551541c580e338206f1f677835d427c92de216906324b8fbf6906106459033908690600401612358565b600060405180830381600087803b15801561065f57600080fd5b505af1158015610673573d6000803e3d6000fd5b505060405163b36543a960e01b8152600092506001600160a01b037f000000000000000000000000b486cce9b4507a67db147b0802d5673774c8d27816915063b36543a9906106c89033908690600401612358565b602060405180830381865afa1580156106e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610709919061239a565b905060004290506000610735604051806060016040528088815260200185815260200184815250610c29565b9050610742600782610f14565b602086015186516007547fd3c3cd829e4e37d5baaf10abace26b24e0046e20500c999380410f807edfcda09061078890600190600160281b900464ffffffffff166123c9565b6040805164ffffffffff909216825260208201889052810186905260600160405180910390a3505050505050565b60405163248f667760e01b8152600090730a0d66bafda8c8838281084d9c3d68dd9a6fc2749063248f6677906107f09085906004016123ee565b602060405180830381865af415801561080d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610831919061239a565b92915050565b60006108436007611064565b905090565b60006000805160206126ff83398151915260028360405160200161086c919061241f565b60408051601f198184030181529082905261088691612455565b602060405180830381855afa1580156108a3573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906108c6919061239a565b6108319190612487565b60006108da611c1a565b838152602081018390526108ed816108f5565b949350505050565b6040516314d2f97b60e11b81526000907388c2c6a7535463962a34757fe63cc4f296381aba906329a5f2f6906107f09085906004016124bf565b60058054600181019091558451602086015161094b9190610e6a565b610968576040516379fae7af60e01b815260040160405180910390fd5b606086015160ff1660006001600160a01b037f000000000000000000000000982530673ce9e5efa02438c694d48327aa4fb592166370f7b3618a8a8a30866109b160018a6124e7565b600581106109c1576109c16124a9565b01546040518663ffffffff1660e01b81526004016109e39594939291906124fa565b6020604051808303816000875af1158015610a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a26919061256b565b905060007f00000000000000000000000050045b05cb1c76410783d8a3e5625a99d57293396001600160a01b03166336344873888885338a6040518663ffffffff1660e01b8152600401610a7e9594939291906125aa565b6020604051808303816000875af1158015610a9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac1919061256b565b905060007f000000000000000000000000bb28555e989799478442483cd1f2d370a14e2c426001600160a01b031663431a717589898686338c6040518763ffffffff1660e01b8152600401610b1b969594939291906125e9565b6020604051808303816000875af1158015610b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5e919061256b565b604080516060810182526001600160a01b038087168252858116602080840191825282861684860190815260008c815260068352869020855181549086166001600160a01b03199182161782559351600182018054918716918616919091179055905160029091018054919094169216919091179091558c01518c51925193945090929091907f38b2d18bb65cc91d7b436014cf44c8298b13bee60cc18d9e8efec26d1df3189090610c13908a908c90612631565b60405180910390a3505050505050505050505050565b6000610c33611c38565b8251518152825160209081015181830152830151816002602002015260408301516060820152610c62816107b6565b9392505050565b6000610c73611c56565b8351518152835160209081015190820152835160409081015190820152835160609081015190820152835160809081015190820152610cb0611c56565b845160a001518152845160c001516020820152845160e00151604080830191909152855161010001516060830152855161012001516080808401919091528151908101909152610d2e9080610d0485610d37565b8152602001610d1284610d37565b81526020018660000151815260200186602001518152506107b6565b95945050505050565b604051630926f44b60e31b815260009073d2f6c828606ad8e985008cd825012f269b50cd5890634937a258906107f0908590600401612645565b60008160058110610d8157600080fd5b0154905081565b6040516304b98e1d60e31b815260009073f8e637e5c9ec3a8d8fa8843a6df833348e1f1e66906325cc70e8906107f090859060040161266d565b610dca611c74565b60408051808201909152600080825260208201526000610de8611c8c565b84518152602080860151828201526040805180820182527f171e826ad4a870fd925e0bf0e87884e70e080879c2205ef10114f28a3b6f6dd781527f2bd407d897fbbca9f88adfd2d15252e69de8c1564eb4d3d27162e259172f1a1d8184015281519283019091528282529094509250610e618484610c69565b93959294505050565b6000806000805160206126ff833981519152848509905060006000805160206126ff833981519152848509905060006000805160206126ff833981519152826000805160206126ff83398151915285620292fc0908905060006000805160206126ff83398151915280846000805160206126ff83398151915287620292f809096001089050610f0882826000805160206126ff8339815191526110b4565b15979650505050505050565b8154600160281b900464ffffffffff16610f2f816001612695565b835464ffffffffff91909116600160281b0269ffffffffff0000000000199091161783558160005b81856001016000610f6884876110ef565b64ffffffffff168152602081019190915260400160002055600183161561105d576000610f9f82610f9a6001876123c9565b6110ef565b60408051808201825264ffffffffff8316600090815260018a01602090815290839020548252810186905290516314d2f97b60e11b81529192507388c2c6a7535463962a34757fe63cc4f296381aba916329a5f2f691611001916004016124bf565b602060405180830381865af415801561101e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611042919061239a565b647fffffffff600195861c1694909350919091019050610f57565b5050505050565b8054600090600160281b900464ffffffffff1660015b8164ffffffffff168160ff166001901b64ffffffffff1610156110a957806110a1816126b3565b91505061107a565b6108ed848383611114565b6000838381116110cb576110c883826126d2565b90505b82806110d9576110d9612471565b60006110e586846124e7565b0895945050505050565b60008161110a60ff851664ff00000000602087901b166123c9565b610c629190612695565b600060208260ff16111561113b57604051633e104c7760e01b815260040160405180910390fd5b8264ffffffffff1660000361115a57611153826111e0565b9050610c62565b60006111678360016126e5565b60ff166001600160401b0381111561118157611181611cc4565b6040519080825280602002602001820160405280156111aa578160200160208202803683370190505b5090506111b98585858461186d565b808360ff16815181106111ce576111ce6124a9565b60200260200101519150509392505050565b60008160ff1660000361121457507f0ef71f46e11a513c599eed9dd03576c33439bcfb1cee155316f90541e41649ba919050565b8160ff1660010361124657507f06928e817d2804a3713efd102bae900c9ab3e8e0b0c6c20f8613bd3b0423a891919050565b8160ff1660020361127857507f2a06fb0b739b402c34dc752d8417b9cd67b7f7cabe4b06b5d995053791fcede4919050565b8160ff166003036112aa57507f04265868d2e705f48d3ae49f7749e67a587dafdb569c1d7334675496046eaad6919050565b8160ff166004036112dc57507f08e4b5d410c8de929132c214ea600b5f252fa14aabb97ea67cda5bb4e0ebeec8919050565b8160ff1660050361130e57507f11dc55d21b17daf8e60253c2a43d519039ba968733cf7c9d5df6155939e1a6d8919050565b8160ff1660060361134057507f30553f8216db90854953edd47602897f897104d5b0d65a5ce000981c51da32e0919050565b8160ff1660070361137257507f0690bfb582c7502ff6d15d519740ecd73d652b7a14dc82bfd250613ee8e04076919050565b8160ff166008036113a457507f1ea63a974336db6c0423e719d3f0e11494266237dda3a40de3cb761044366359919050565b8160ff166009036113d657507f1e73f08f6e5e4bb9c2096cc4587526ebfd033c222f4a27e97119c867c36a0d3a919050565b8160ff16600a0361140857507f10f7b76489e9c36644736c33c600d1bcedd465fd0aff3027e67b02e13875272d919050565b8160ff16600b0361143a57507f05e0136534f74776d69646bd0bd94519e63af45734405f479382d8400514c1a6919050565b8160ff16600c0361146c57507f1f336d6d45d293180c75964e99a7599d44cac2ad447c202c3e1973b0322cf990919050565b8160ff16600d0361149e57507f2582b5cdefe032d75373f0ede9171406137e93e7d44405a0b0a409c1c7391380919050565b8160ff16600e036114d057507f2ec047dd616221873c234f36461080c3e760644bb519ebdb49eb9645215e0edc919050565b8160ff16600f0361150257507f128fb9ad5b2d8e694bec0888ff95609c15b2a96ae80a34946c953dc503e46fb6919050565b8160ff1660100361153457507f199cd1f5b757c285023767abbe9bbb318da4e1fd375b5a001b54a0f3901ea7d3919050565b8160ff1660110361156657507f2b8342160822355808db759147a7d6f61de451bd5bb88f9db2eb406ea68b8138919050565b8160ff1660120361159857507f1874217e8e1dbc51c571a2db1103bf47c3e66a59305ca48bbcee6ad1c8cc5751919050565b8160ff166013036115ca57507f2c849a73ab21c9e88e1d711f221863e2a94eb58f3eb42dde575301451f3ec5c8919050565b8160ff166014036115fc57507f1713f3e3dc5e2393bd31ccc0cdd8601bdee3198cf34d566bb60cfab13e5a0873919050565b8160ff1660150361162e57507f2ce2c1fb109ad6574570826774ecfca3e04866bb5a3963962b873646db6641f3919050565b8160ff1660160361166057507f2560496c1138c827f1efb407d0cdb9d6ec9539b0957dfb67de2776e6026d630f919050565b8160ff1660170361169257507f1d71ada9e49baeb4a2cf26be37d3bc680554995ef6706105e93978ba71cacf94919050565b8160ff166018036116c457507f19b336a1e0a933e2a8f97d97322dcee843a2d9a2401bece52a3a25ddd5bb6bc9919050565b8160ff166019036116f657507f1b6367322bac9f24889900d310e2feaa0021516fac77470aea078e89335d3fcf919050565b8160ff16601a0361172857507f24cb019b59431c232413f66b041923214f7a8a7489caa05b66860f1c3c76d3b1919050565b8160ff16601b0361175a57507f132e4ff3e4ba890f1610efd4d2f69700b825514d557b82663878a56e2acef41c919050565b8160ff16601c0361178c57507f0845dd838ca63b2f68775aac8513bd692d26f511698206f3c6ce2b4100dd8d8f919050565b8160ff16601d036117be57507f14b46e659dc4072fc64a18d44911c4a303b45f1296c3cb7dec77f269bee9b5df919050565b8160ff16601e036117f057507f2b59c2651b412c029efa38f835ac1b1b5bdaf89dcb2e4bc9219e7d77c65e776a919050565b8160ff16601f0361182257507f216b9fa3ac3724cf1ec6caf5a66dd85cae3aee727e00d2a0a59f273df3401f10919050565b8160ff1660200361185457507f1d90601a0c76d2f39824f6dc198fb3b48cbd0231516c8f6208e56ea741c341f9919050565b6040516310a2ea0560e21b815260040160405180910390fd5b60208260ff16111561189257604051633e104c7760e01b815260040160405180910390fd5b8264ffffffffff166000036118ba5760405163bb5e95dd60e01b815260040160405180910390fd5b60006118c76001856123c9565b90506001811660000361191f578460010160006118e56000846110ef565b64ffffffffff168152602001908152602001600020548260008151811061190e5761190e6124a9565b602002602001018181525050611949565b61192960006111e0565b8260008151811061193c5761193c6124a9565b6020026020010181815250505b60005b8360ff168160ff161015611c125760018216600003611a45577388c2c6a7535463962a34757fe63cc4f296381aba6329a5f2f66040518060400160405280868560ff168151811061199f5761199f6124a9565b602002602001015181526020016119b5856111e0565b8152506040518263ffffffff1660e01b81526004016119d491906124bf565b602060405180830381865af41580156119f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a15919061239a565b83611a218360016126e5565b60ff1681518110611a3457611a346124a9565b602002602001018181525050611bff565b6000611a528260016126e5565b60ff168664ffffffffff16901c64ffffffffff16905060018364ffffffffff16901c64ffffffffff16811115611af7576000876001016000611aab856001611a9a91906126e5565b60018864ffffffffff16901c6110ef565b64ffffffffff1681526020019081526020016000205490508085846001611ad291906126e5565b60ff1681518110611ae557611ae56124a9565b60200260200101818152505050611bfd565b6000876001016000611b1085600188610f9a91906123c9565b64ffffffffff1681526020019081526020016000205490507388c2c6a7535463962a34757fe63cc4f296381aba6329a5f2f66040518060400160405280848152602001888760ff1681518110611b6857611b686124a9565b60200260200101518152506040518263ffffffff1660e01b8152600401611b8f91906124bf565b602060405180830381865af4158015611bac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd0919061239a565b85611bdc8560016126e5565b60ff1681518110611bef57611bef6124a9565b602002602001018181525050505b505b647fffffffff600192831c16910161194c565b505050505050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b6040518060200160405280611c87611c8c565b905290565b604051806101400160405280600a906020820280368337509192915050565b600060208284031215611cbd57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b0381118282101715611cfd57611cfd611cc4565b60405290565b604051601f8201601f191681016001600160401b0381118282101715611d2b57611d2b611cc4565b604052919050565b600060408284031215611d4557600080fd5b604051604081018181106001600160401b0382111715611d6757611d67611cc4565b604052823581526020928301359281019290925250919050565b600082601f830112611d9257600080fd5b81356001600160401b03811115611dab57611dab611cc4565b611dbe601f8201601f1916602001611d03565b818152846020838601011115611dd357600080fd5b816020850160208301376000918101602001919091529392505050565b600080600060808486031215611e0557600080fd5b611e0f8585611d33565b925060408401356001600160401b0380821115611e2b57600080fd5b611e3787838801611d81565b93506060860135915080821115611e4d57600080fd5b50611e5a86828701611d81565b9150509250925092565b600060808284031215611e7657600080fd5b82601f830112611e8557600080fd5b604051608081018181106001600160401b0382111715611ea757611ea7611cc4565b604052806080840185811115611ebc57600080fd5b845b81811015611ed6578035835260209283019201611ebe565b509195945050505050565b60006020808385031215611ef457600080fd5b82356001600160401b0380821115611f0b57600080fd5b818501915085601f830112611f1f57600080fd5b813581811115611f3157611f31611cc4565b8060051b9150611f42848301611d03565b8181529183018401918481019088841115611f5c57600080fd5b938501935b83851015611f7a57843582529385019390850190611f61565b98975050505050505050565b60008060408385031215611f9957600080fd5b50508035926020909101359150565b600060408284031215611fba57600080fd5b82601f830112611fc957600080fd5b604051604081018181106001600160401b0382111715611feb57611feb611cc4565b8060405250806040840185811115611ebc57600080fd5b803560ff8116811461201357600080fd5b919050565b6001600160a01b038116811461202d57600080fd5b50565b803561201381612018565b80356002811061201357600080fd5b60008060008060008086880361014081121561206557600080fd5b873596506080601f198201121561207b57600080fd5b50604051608081018181106001600160401b038211171561209e5761209e611cc4565b6040526120ad60208901612002565b81526120bb60408901612002565b60208201526120cc60608901612002565b60408201526120dd60808901612002565b606082015294506120f18860a08901611d33565b93506120ff60e08801612030565b925061210e6101008801612030565b915061211d610120880161203b565b90509295509295509295565b60006080828403121561213b57600080fd5b604051606081018181106001600160401b038211171561215d5761215d611cc4565b60405261216a8484611d33565b815260408301356020820152606083013560408201528091505092915050565b60008082840361018081121561219f57600080fd5b610140808212156121af57600080fd5b604051915060208083018381106001600160401b03821117156121d4576121d4611cc4565b604052601f860187136121e657600080fd5b6121ee611cda565b91860191808884111561220057600080fd5b875b848110156122195780358352918301918301612202565b5080855250505081935061222d8682611d33565b925050509250929050565b600060a0828403121561224a57600080fd5b82601f83011261225957600080fd5b60405160a081018181106001600160401b038211171561227b5761227b611cc4565b6040528060a0840185811115611ebc57600080fd5b6000606082840312156122a257600080fd5b82601f8301126122b157600080fd5b604051606081018181106001600160401b03821117156122d3576122d3611cc4565b604052806060840185811115611ebc57600080fd5b83516101a08201908260005b600a8110156123135782518252602092830192909101906001016122f4565b50508451610140840152506020909301516101608201526101800152919050565b60005b8381101561234f578181015183820152602001612337565b50506000910152565b60018060a01b03831681526040602082015260008251806040840152612385816060850160208701612334565b601f01601f1916919091016060019392505050565b6000602082840312156123ac57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff8281168282160390808211156123e7576123e76123b3565b5092915050565b60808101818360005b60048110156124165781518352602092830192909101906001016123f7565b50505092915050565b815160009082906020808601845b838110156124495781518552938201939082019060010161242d565b50929695505050505050565b60008251612467818460208701612334565b9190910192915050565b634e487b7160e01b600052601260045260246000fd5b6000826124a457634e487b7160e01b600052601260045260246000fd5b500690565b634e487b7160e01b600052603260045260246000fd5b60408101818360005b60028110156124165781518352602092830192909101906001016124c8565b81810381811115610831576108316123b3565b60006101208201905086825260ff865116602083015260ff602087015116604083015260ff604087015116606083015260ff606087015116608083015261254e60a083018680518252602090810151910152565b6001600160a01b039390931660e082015261010001529392505050565b60006020828403121561257d57600080fd5b8151610c6281612018565b600281106125a657634e487b7160e01b600052602160045260246000fd5b9052565b6001600160a01b038681168252858116602083015284811660408301528316606082015260a081016125df6080830184612588565b9695505050505050565b6001600160a01b0387811682528681166020830152858116604083015284811660608301528316608082015260c0810161262660a0830184612588565b979650505050505050565b82815260408101610c626020830184612588565b60a08101818360005b600581101561241657815183526020928301929091019060010161264e565b60608101818360005b6003811015612416578151835260209283019290910190600101612676565b64ffffffffff8181168382160190808211156123e7576123e76123b3565b600060ff821660ff81036126c9576126c96123b3565b60010192915050565b80820180821115610831576108316123b3565b60ff8181168382160190811115610831576108316123b356fe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a2646970667358221220cd6cb498a0a85d0e5e5af107d53349e78c14508c00eabc21b88f5a675db1719564736f6c63430008140033

Block Transaction Gas Used Reward
view all blocks sequenced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.