OP Sepolia Testnet

Contract

0xbBb6f1B4232F993e5a026217a3D596B332062CB3

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
210951552024-12-12 8:40:5035 days ago1733992850
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
210947322024-12-12 8:26:4435 days ago1733992004
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
207943232024-12-05 9:33:0642 days ago1733391186
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
207912742024-12-05 7:51:2842 days ago1733385088
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
206998612024-12-03 5:04:2244 days ago1733202262
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
206718462024-12-02 13:30:3245 days ago1733146232
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
206708392024-12-02 12:56:5845 days ago1733144218
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
198760942024-11-14 3:25:2863 days ago1731554728
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
198723692024-11-14 1:21:1863 days ago1731547278
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
198707402024-11-14 0:27:0063 days ago1731544020
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
198554262024-11-13 15:56:3264 days ago1731513392
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
198540502024-11-13 15:10:4064 days ago1731510640
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
198539692024-11-13 15:07:5864 days ago1731510478
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175797282024-09-21 23:39:56116 days ago1726961996
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175792592024-09-21 23:24:18116 days ago1726961058
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175646992024-09-21 15:18:58117 days ago1726931938
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175603612024-09-21 12:54:22117 days ago1726923262
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175602812024-09-21 12:51:42117 days ago1726923102
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175599802024-09-21 12:41:40117 days ago1726922500
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175598682024-09-21 12:37:56117 days ago1726922276
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175566592024-09-21 10:50:58117 days ago1726915858
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175566132024-09-21 10:49:26117 days ago1726915766
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175562712024-09-21 10:38:02117 days ago1726915082
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175557582024-09-21 10:20:56117 days ago1726914056
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
175492652024-09-21 6:44:30117 days ago1726901070
0xbBb6f1B4...332062CB3
 Contract Creation0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MessageProcessorFactory

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 22 : MessageProcessorFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import { Params } from "./utilities/Params.sol";
import { DomainObjs } from "./utilities/DomainObjs.sol";
import { MessageProcessor } from "./MessageProcessor.sol";
import { IMessageProcessorFactory } from "./interfaces/IMPFactory.sol";

/// @title MessageProcessorFactory
/// @notice A factory contract which deploys MessageProcessor contracts.
contract MessageProcessorFactory is Params, DomainObjs, IMessageProcessorFactory {
  /// @inheritdoc IMessageProcessorFactory
  function deploy(
    address _verifier,
    address _vkRegistry,
    address _poll,
    address _owner,
    Mode _mode
  ) public returns (address messageProcessorAddr) {
    // deploy MessageProcessor for this Poll
    MessageProcessor messageProcessor = new MessageProcessor(_verifier, _vkRegistry, _poll, _owner, _mode);
    messageProcessorAddr = address(messageProcessor);
  }
}

File 2 of 22 : 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 22 : 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 22 : 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 5 of 22 : Pairing.sol
// SPDX-License-Identifier: MIT
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

// 2019 OKIMS

pragma solidity ^0.8.20;

/// @title Pairing
/// @notice A library implementing the alt_bn128 elliptic curve operations.
library Pairing {
  uint256 public constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;

  struct G1Point {
    uint256 x;
    uint256 y;
  }

  // Encoding of field elements is: X[0] * z + X[1]
  struct G2Point {
    uint256[2] x;
    uint256[2] y;
  }

  /// @notice custom errors
  error PairingAddFailed();
  error PairingMulFailed();
  error PairingOpcodeFailed();

  /// @notice The negation of p, i.e. p.plus(p.negate()) should be zero.
  function negate(G1Point memory p) internal pure returns (G1Point memory) {
    // The prime q in the base field F_q for G1
    if (p.x == 0 && p.y == 0) {
      return G1Point(0, 0);
    } else {
      return G1Point(p.x, PRIME_Q - (p.y % PRIME_Q));
    }
  }

  /// @notice r Returns the sum of two points of G1.
  function plus(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
    uint256[4] memory input;
    input[0] = p1.x;
    input[1] = p1.y;
    input[2] = p2.x;
    input[3] = p2.y;
    bool success;

    // solhint-disable-next-line no-inline-assembly
    assembly {
      success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
      // Use "invalid" to make gas estimation work
      switch success
      case 0 {
        invalid()
      }
    }

    if (!success) {
      revert PairingAddFailed();
    }
  }

  /// @notice r Return the product of a point on G1 and a scalar, i.e.
  ///         p == p.scalarMul(1) and p.plus(p) == p.scalarMul(2) for all
  ///         points p.
  function scalarMul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
    uint256[3] memory input;
    input[0] = p.x;
    input[1] = p.y;
    input[2] = s;
    bool success;
    // solhint-disable-next-line no-inline-assembly
    assembly {
      success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
      // Use "invalid" to make gas estimation work
      switch success
      case 0 {
        invalid()
      }
    }

    if (!success) {
      revert PairingMulFailed();
    }
  }

  /// @return isValid The result of computing the pairing check
  ///         e(p1[0], p2[0]) *  .... * e(p1[n], p2[n]) == 1
  ///        For example,
  ///        pairing([P1(), P1().negate()], [P2(), P2()]) should return true.
  function pairing(
    G1Point memory a1,
    G2Point memory a2,
    G1Point memory b1,
    G2Point memory b2,
    G1Point memory c1,
    G2Point memory c2,
    G1Point memory d1,
    G2Point memory d2
  ) internal view returns (bool isValid) {
    G1Point[4] memory p1;
    p1[0] = a1;
    p1[1] = b1;
    p1[2] = c1;
    p1[3] = d1;

    G2Point[4] memory p2;
    p2[0] = a2;
    p2[1] = b2;
    p2[2] = c2;
    p2[3] = d2;

    uint256 inputSize = 24;
    uint256[] memory input = new uint256[](inputSize);

    for (uint8 i = 0; i < 4; ) {
      uint8 j = i * 6;
      input[j + 0] = p1[i].x;
      input[j + 1] = p1[i].y;
      input[j + 2] = p2[i].x[0];
      input[j + 3] = p2[i].x[1];
      input[j + 4] = p2[i].y[0];
      input[j + 5] = p2[i].y[1];

      unchecked {
        i++;
      }
    }

    uint256[1] memory out;
    bool success;

    // solhint-disable-next-line no-inline-assembly
    assembly {
      success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
      // Use "invalid" to make gas estimation work
      switch success
      case 0 {
        invalid()
      }
    }

    if (!success) {
      revert PairingOpcodeFailed();
    }

    isValid = out[0] != 0;
  }
}

File 6 of 22 : 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 22 : 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 22 : 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 22 : 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 22 : SnarkCommon.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { Pairing } from "./Pairing.sol";

/// @title SnarkCommon
/// @notice a Contract which holds a struct
/// representing a Groth16 verifying key
contract SnarkCommon {
  /// @notice a struct representing a Groth16 verifying key
  struct VerifyingKey {
    Pairing.G1Point alpha1;
    Pairing.G2Point beta2;
    Pairing.G2Point gamma2;
    Pairing.G2Point delta2;
    Pairing.G1Point[] ic;
  }
}

File 11 of 22 : 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 12 of 22 : 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 13 of 22 : IMessageProcessor.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

/// @title IMessageProcessor
/// @notice MessageProcessor interface
interface IMessageProcessor {
  /// @notice Get the result of whether there are unprocessed messages left
  /// @return Whether there are unprocessed messages left
  function processingComplete() external view returns (bool);

  /// @notice Get the commitment to the state and ballot roots
  /// @return The commitment to the state and ballot roots
  function sbCommitment() external view returns (uint256);

  /// @notice Get public circuit inputs.
  /// @param _currentMessageBatchIndex The current processed batch index
  /// @param _newSbCommitment The new state root and ballot root commitment
  ///                         after all messages are processed
  /// @return publicInputs public circuit inputs
  function getPublicCircuitInputs(
    uint256 _currentMessageBatchIndex,
    uint256 _newSbCommitment
  ) external view returns (uint256[] memory);
}

File 14 of 22 : 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 22 : IPoll.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import { DomainObjs } from "../utilities/DomainObjs.sol";
import { IMACI } from "./IMACI.sol";
import { AccQueue } from "../trees/AccQueue.sol";

/// @title IPoll
/// @notice Poll interface
interface IPoll {
  /// @notice The number of messages which have been processed and the number of signups
  /// @return numSignups The number of signups
  /// @return numMsgs The number of messages sent by voters
  function numSignUpsAndMessages() external view returns (uint256 numSignups, uint256 numMsgs);

  /// @notice Allows anyone to publish a message (an encrypted command and signature).
  /// This function also enqueues the message.
  /// @param _message The message to publish
  /// @param _encPubKey An ephemeral public key which can be combined with the
  /// coordinator's private key to generate an ECDH shared key with which
  /// to encrypt the message.
  function publishMessage(DomainObjs.Message memory _message, DomainObjs.PubKey calldata _encPubKey) external;

  /// @notice The second step of merging the MACI state AccQueue. This allows the
  /// ProcessMessages circuit to access the latest state tree and ballots via
  /// currentSbCommitment.
  function mergeMaciState() external;

  /// @notice The first step in merging the message AccQueue so that the
  /// ProcessMessages circuit can access the message root.
  /// @param _numSrQueueOps The number of subroot queue operations to perform
  function mergeMessageAqSubRoots(uint256 _numSrQueueOps) external;

  /// @notice The second step in merging the message AccQueue so that the
  /// ProcessMessages circuit can access the message root.
  function mergeMessageAq() external;

  /// @notice Returns the Poll's deploy time and duration
  /// @return _deployTime The deployment timestamp
  /// @return _duration The duration of the poll
  function getDeployTimeAndDuration() external view returns (uint256 _deployTime, uint256 _duration);

  /// @notice Get the result of whether the MACI contract's stateAq has been merged by this contract
  /// @return Whether the MACI contract's stateAq has been merged by this contract
  function stateMerged() external view returns (bool);

  /// @notice Get the depths of the merkle trees
  /// @return intStateTreeDepth The depth of the state tree
  /// @return messageTreeSubDepth The subdepth of the message tree
  /// @return messageTreeDepth The depth of the message tree
  /// @return voteOptionTreeDepth The subdepth of the vote option tree
  function treeDepths()
    external
    view
    returns (uint8 intStateTreeDepth, uint8 messageTreeSubDepth, uint8 messageTreeDepth, uint8 voteOptionTreeDepth);

  /// @notice Get the external contracts
  /// @return maci The IMACI contract
  /// @return messageAq The AccQueue contract
  function extContracts() external view returns (IMACI maci, AccQueue messageAq);

  /// @notice Get the hash of coordinator's public key
  /// @return _coordinatorPubKeyHash the hash of coordinator's public key
  function coordinatorPubKeyHash() external view returns (uint256 _coordinatorPubKeyHash);

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

  /// @notice Get the dynamic depth of the state tree at the time of poll
  /// finalization (based on the number of leaves inserted)
  function actualStateTreeDepth() external view returns (uint8);
}

File 16 of 22 : IVerifier.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

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

/// @title IVerifier
/// @notice an interface for a Groth16 verifier contract
interface IVerifier {
  /// @notice Verify a zk-SNARK proof
  /// @param _proof The proof
  /// @param vk The verifying key
  /// @param inputs The public inputs to the circuit
  /// @return Whether the proof is valid given the verifying key and public
  ///          input. Note that this function only supports one public input.
  ///          Refer to the Semaphore source code for a verifier that supports
  ///          multiple public inputs.
  function verify(
    uint256[8] memory _proof,
    SnarkCommon.VerifyingKey memory vk,
    uint256[] memory inputs
  ) external view returns (bool);
}

File 17 of 22 : IVkRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

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

/// @title IVkRegistry
/// @notice VkRegistry interface
interface IVkRegistry {
  /// @notice Get the tally verifying key
  /// @param _stateTreeDepth The state tree depth
  /// @param _intStateTreeDepth The intermediate state tree depth
  /// @param _voteOptionTreeDepth The vote option tree depth
  /// @param _mode QV or Non-QV
  /// @return The verifying key
  function getTallyVk(
    uint256 _stateTreeDepth,
    uint256 _intStateTreeDepth,
    uint256 _voteOptionTreeDepth,
    DomainObjs.Mode _mode
  ) external view returns (SnarkCommon.VerifyingKey memory);

  /// @notice Get the process verifying key
  /// @param _stateTreeDepth The state tree depth
  /// @param _messageTreeDepth The message tree depth
  /// @param _voteOptionTreeDepth The vote option tree depth
  /// @param _messageBatchSize The message batch size
  /// @param _mode QV or Non-QV
  /// @return The verifying key
  function getProcessVk(
    uint256 _stateTreeDepth,
    uint256 _messageTreeDepth,
    uint256 _voteOptionTreeDepth,
    uint256 _messageBatchSize,
    DomainObjs.Mode _mode
  ) external view returns (SnarkCommon.VerifyingKey memory);
}

File 18 of 22 : MessageProcessor.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { AccQueue } from "./trees/AccQueue.sol";
import { IMACI } from "./interfaces/IMACI.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IPoll } from "./interfaces/IPoll.sol";
import { SnarkCommon } from "./crypto/SnarkCommon.sol";
import { Hasher } from "./crypto/Hasher.sol";
import { IVerifier } from "./interfaces/IVerifier.sol";
import { IVkRegistry } from "./interfaces/IVkRegistry.sol";
import { IMessageProcessor } from "./interfaces/IMessageProcessor.sol";
import { CommonUtilities } from "./utilities/CommonUtilities.sol";
import { DomainObjs } from "./utilities/DomainObjs.sol";

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

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

  /// @inheritdoc IMessageProcessor
  bool public processingComplete;

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

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

  /// @inheritdoc IMessageProcessor
  uint256 public sbCommitment;

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

  /// @notice Create a new instance
  /// @param _verifier The Verifier contract address
  /// @param _vkRegistry The VkRegistry contract address
  /// @param _poll The Poll contract address
  /// @param _mpOwner The owner of the MessageProcessor contract
  /// @param _mode Voting mode
  constructor(
    address _verifier,
    address _vkRegistry,
    address _poll,
    address _mpOwner,
    Mode _mode
  ) payable Ownable(_mpOwner) {
    verifier = IVerifier(_verifier);
    vkRegistry = IVkRegistry(_vkRegistry);
    poll = IPoll(_poll);
    mode = _mode;
  }

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

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

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

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

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

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

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

      currentMessageBatchIndex = numMessages;

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

    if (!verifyProcessProof(currentMessageBatchIndex, _newSbCommitment, _proof)) {
      revert InvalidProcessMessageProof();
    }

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

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

  /// @inheritdoc IMessageProcessor
  function getPublicCircuitInputs(
    uint256 _currentMessageBatchIndex,
    uint256 _newSbCommitment
  ) public view override returns (uint256[] memory publicInputs) {
    (, uint8 messageTreeSubDepth, uint8 messageTreeDepth, ) = poll.treeDepths();
    (, AccQueue messageAq) = poll.extContracts();
    uint256 coordinatorPubKeyHash = poll.coordinatorPubKeyHash();
    uint256 messageBatchSize = TREE_ARITY ** messageTreeSubDepth;
    (uint256 numSignUps, uint256 numMessages) = poll.numSignUpsAndMessages();
    (uint256 deployTime, uint256 duration) = poll.getDeployTimeAndDuration();
    uint256 batchEndIndex = _currentMessageBatchIndex + messageBatchSize;

    if (batchEndIndex > numMessages) {
      batchEndIndex = numMessages;
    }

    publicInputs = new uint256[](9);
    publicInputs[0] = numSignUps;
    publicInputs[1] = deployTime + duration;
    publicInputs[2] = messageAq.getMainRoot(messageTreeDepth);
    publicInputs[3] = poll.actualStateTreeDepth();
    publicInputs[4] = batchEndIndex;
    publicInputs[5] = _currentMessageBatchIndex;
    publicInputs[6] = coordinatorPubKeyHash;
    publicInputs[7] = (sbCommitment == 0 ? poll.currentSbCommitment() : sbCommitment);
    publicInputs[8] = _newSbCommitment;
  }

  /// @notice Verify the proof for processMessage
  /// @dev used to update the sbCommitment
  /// @param _currentMessageBatchIndex The current message batch index
  /// @param _newSbCommitment The new state root and ballot root commitment
  ///                         after all messages are processed
  /// @param _proof The zk-SNARK proof
  /// @return isValid Whether the proof is valid
  function verifyProcessProof(
    uint256 _currentMessageBatchIndex,
    uint256 _newSbCommitment,
    uint256[8] calldata _proof
  ) public view returns (bool isValid) {
    // get the tree depths
    (, uint8 messageTreeSubDepth, uint8 messageTreeDepth, uint8 voteOptionTreeDepth) = poll.treeDepths();
    (IMACI maci, ) = poll.extContracts();
    uint256[] memory publicCircuitInputs = getPublicCircuitInputs(_currentMessageBatchIndex, _newSbCommitment);

    // Get the verifying key from the VkRegistry
    VerifyingKey memory vk = vkRegistry.getProcessVk(
      maci.stateTreeDepth(),
      messageTreeDepth,
      voteOptionTreeDepth,
      TREE_ARITY ** messageTreeSubDepth,
      mode
    );

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

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

File 19 of 22 : 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 20 of 22 : CommonUtilities.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { IPoll } from "../interfaces/IPoll.sol";

/// @title CommonUtilities
/// @notice A contract that holds common utilities
/// which are to be used by multiple contracts
/// namely Tally and MessageProcessor
contract CommonUtilities {
  error VotingPeriodNotPassed();

  /// @notice common function for MessageProcessor, and Tally
  /// @param _poll the poll to be checked
  function _votingPeriodOver(IPoll _poll) internal view {
    (uint256 deployTime, uint256 duration) = _poll.getDeployTimeAndDuration();
    // Require that the voting period is over
    uint256 secondsPassed = block.timestamp - deployTime;
    if (secondsPassed <= duration) {
      revert VotingPeriodNotPassed();
    }
  }
}

File 21 of 22 : 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 22 of 22 : 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;
  }
}

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

Contract ABI

[{"inputs":[],"name":"MESSAGE_DATA_LENGTH","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_verifier","type":"address"},{"internalType":"address","name":"_vkRegistry","type":"address"},{"internalType":"address","name":"_poll","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"enum DomainObjs.Mode","name":"_mode","type":"uint8"}],"name":"deploy","outputs":[{"internalType":"address","name":"messageProcessorAddr","type":"address"}],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50612455806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063363448731461003b578063683f3dc31461006b575b600080fd5b61004e6100493660046100f8565b610085565b6040516001600160a01b0390911681526020015b60405180910390f35b610073600a81565b60405160ff9091168152602001610062565b6000808686868686604051610099906100cf565b6100a7959493929190610165565b604051809103906000f0801580156100c3573d6000803e3d6000fd5b50979650505050505050565b612264806101bc83390190565b80356001600160a01b03811681146100f357600080fd5b919050565b600080600080600060a0868803121561011057600080fd5b610119866100dc565b9450610127602087016100dc565b9350610135604087016100dc565b9250610143606087016100dc565b915060808601356002811061015757600080fd5b809150509295509295909350565b6001600160a01b038681168252858116602083015284811660408301528316606082015260a08101600283106101ab57634e487b7160e01b600052602160045260246000fd5b826080830152969550505050505056fe6101006040526040516200226438038062002264833981016040819052620000279162000124565b816001600160a01b0381166200005757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006281620000b7565b506001600160a01b0380861660a05284811660c05283166080528060018111156200009157620000916200019b565b60e0816001811115620000a857620000a86200019b565b815250505050505050620001b1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146200011f57600080fd5b919050565b600080600080600060a086880312156200013d57600080fd5b620001488662000107565b9450620001586020870162000107565b9350620001686040870162000107565b9250620001786060870162000107565b91506080860151600281106200018d57600080fd5b809150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e051611ff462000270600039600081816101cc0152610ac201526000818161016a0152610a240152600081816102000152610b600152600081816102ef0152818161035a015281816103e40152818161046a01528181610500015281816105880152818161071b0152818161082e015281816109050152818161099001528181610dbd01528181610e0e01528181610eb001528181610f4b0152818161106d015281816110fa01526112080152611ff46000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c8063683f3dc3116100b85780639cfced971161007c5780639cfced97146102d7578063a1175279146102ea578063b1a263d314610311578063bea140b314610324578063d13181b814610337578063f2fde38b1461034057600080fd5b8063683f3dc314610285578063715018a61461029f5780637a38d18f146102a95780638763d0c4146102b25780638da5cb5b146102c657600080fd5b80633d6528a1116100ff5780633d6528a1146102225780633dfb88b21461023957806358bfc3791461024c5780635bb939951461025f57806362a361bb1461027257600080fd5b8063023650801461013c57806313fb89321461016557806324fab879146101a4578063295a5212146101c75780632b7ac3f3146101fb575b600080fd5b61014f61014a3660046114cd565b610353565b60405161015c919061152a565b60405180910390f35b61018c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161015c565b6101b76101b2366004611556565b6108fd565b604051901515815260200161015c565b6101ee7f000000000000000000000000000000000000000000000000000000000000000081565b60405161015c91906115af565b61018c7f000000000000000000000000000000000000000000000000000000000000000081565b61022b60025481565b60405190815260200161015c565b61022b610247366004611650565b610be8565b61022b61025a3660046116f2565b610c69565b61022b61026d3660046114cd565b610d03565b61022b610280366004611788565b610d28565b61028d600a81565b60405160ff909116815260200161015c565b6102a7610d62565b005b61022b60015481565b6000546101b790600160a01b900460ff1681565b6000546001600160a01b031661018c565b61022b6102e53660046117e8565b610d76565b61018c7f000000000000000000000000000000000000000000000000000000000000000081565b6102a761031f366004611823565b610db0565b61022b610332366004611851565b6112df565b61022b60035481565b6102a761034e3660046118bf565b611319565b60606000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ac98e5df6040518163ffffffff1660e01b8152600401608060405180830381865afa1580156103b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103da91906118f2565b50925092505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bc14ee2b6040518163ffffffff1660e01b81526004016040805180830381865afa15801561043f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104639190611946565b91505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638aa0ba926040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ea9190611980565b905060006104f9856005611a93565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634f367f0f6040518163ffffffff1660e01b81526004016040805180830381865afa15801561055b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057f9190611aa2565b915091506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634909229f6040518163ffffffff1660e01b81526004016040805180830381865afa1580156105e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106079190611aa2565b90925090506000610618868e611ac6565b9050838111156106255750825b6040805160098082526101408201909252906020820161012080368337019050509a50848b60008151811061065c5761065c611ad9565b60209081029190910101526106718284611ac6565b8b60018151811061068457610684611ad9565b6020908102919091010152604051631b9b8aa760e01b815260ff8a1660048201526001600160a01b03891690631b9b8aa790602401602060405180830381865afa1580156106d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106fa9190611980565b8b60028151811061070d5761070d611ad9565b6020026020010181815250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637028bb0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079b9190611aef565b60ff168b6003815181106107b1576107b1611ad9565b602002602001018181525050808b6004815181106107d1576107d1611ad9565b6020026020010181815250508c8b6005815181106107f1576107f1611ad9565b602002602001018181525050868b60068151811061081157610811611ad9565b60209081029190910101526003541561082c576003546108ae565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c17268d96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561088a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ae9190611980565b8b6007815181106108c1576108c1611ad9565b6020026020010181815250508b8b6008815181106108e1576108e1611ad9565b6020026020010181815250505050505050505050505092915050565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ac98e5df6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610961573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098591906118f2565b9350935093505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bc14ee2b6040518163ffffffff1660e01b81526004016040805180830381865afa1580156109eb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0f9190611946565b5090506000610a1e8989610353565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d88ff4f5846001600160a01b031663652c76e46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab39190611aef565b8787610ac08b6005611a93565b7f00000000000000000000000000000000000000000000000000000000000000006040518663ffffffff1660e01b8152600401610b01959493929190611b0a565b600060405180830381865afa158015610b1e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b469190810190611bf7565b60405163352a4d1560e01b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063352a4d1590610b99908b9085908790600401611d55565b602060405180830381865afa158015610bb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bda9190611e29565b9a9950505050505050505050565b60405163248f667760e01b815260009073e0398f7dfac494c530f6404afeac8669abed26799063248f667790610c22908590600401611e4b565b602060405180830381865af4158015610c3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c639190611980565b92915050565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600283604051602001610c9f9190611e7c565b60408051601f1981840301815290829052610cb991611eb2565b602060405180830381855afa158015610cd6573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610cf99190611980565b610c639190611ee1565b6000610d0d6114af565b83815260208101839052610d2081610d28565b949350505050565b6040516314d2f97b60e11b81526000907307490eba00dc4aca6721d052fa4c5002aa077233906329a5f2f690610c22908590600401611f03565b610d6a61135c565b610d746000611389565b565b604051630926f44b60e31b815260009073fd77833f10a29c76a6a0ede235eb651d744d0e2f90634937a25890610c22908590600401611f2b565b610db861135c565b610de17f00000000000000000000000000000000000000000000000000000000000000006113d9565b600054600160a01b900460ff1615610e0c5760405163a7f0397560e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e33b13a06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8e9190611e29565b610eab5760405163e5fe9e1560e01b815260040160405180910390fd5b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ac98e5df6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610f0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3091906118f2565b5092509250506000826005610f459190611a93565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bc14ee2b6040518163ffffffff1660e01b81526004016040805180830381865afa158015610fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fca9190611946565b604051631b9b8aa760e01b815260ff86166004820152909250600091506001600160a01b03831690631b9b8aa790602401602060405180830381865afa158015611018573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103c9190611980565b90508060000361105f5760405163c0b868a560e01b815260040160405180910390fd5b6001546000036111d75760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c17268d96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ed9190611980565b90508060038190555060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634f367f0f6040518163ffffffff1660e01b81526004016040805180830381865afa158015611155573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111799190611aa2565b9150600090506111898683611ee1565b6002839055905081156111d357806000036111bb5785600260008282546111b09190611f53565b909155506111d39050565b80600260008282546111cd9190611f53565b90915550505b5050505b6111e460025488886108fd565b6112045760405160016268f24f60e01b0319815260040160405180910390fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634f367f0f6040518163ffffffff1660e01b81526004016040805180830381865afa158015611263573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112879190611aa2565b915050600060025411156112ad5783600260008282546112a79190611f53565b90915550505b6112d58860025460015460016112c39190611ac6565b6112cd9088611f66565b841115611476565b5050505050505050565b6040516304b98e1d60e31b815260009073bb0e724ce02e5e7edd31e632dc6e59f229a1126d906325cc70e890610c22908590600401611f7d565b61132161135c565b6001600160a01b03811661135057604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b61135981611389565b50565b6000546001600160a01b03163314610d745760405163118cdaa760e01b8152336004820152602401611347565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080826001600160a01b0316634909229f6040518163ffffffff1660e01b81526004016040805180830381865afa158015611419573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143d9190611aa2565b9092509050600061144e8342611f53565b905081811161147057604051635c3017c560e11b815260040160405180910390fd5b50505050565b60038390556000805460ff60a01b1916600160a01b83151502178155600283905560018054916114a583611fa5565b9190505550505050565b60405180604001604052806002906020820280368337509192915050565b600080604083850312156114e057600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b8381101561151f57815187529582019590820190600101611503565b509495945050505050565b60208152600061153d60208301846114ef565b9392505050565b806101008101831015610c6357600080fd5b6000806000610140848603121561156c57600080fd5b83359250602084013591506115848560408601611544565b90509250925092565b600281106115ab57634e487b7160e01b600052602160045260246000fd5b9052565b60208101610c63828461158d565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156115f6576115f66115bd565b60405290565b60405160a0810167ffffffffffffffff811182821017156115f6576115f66115bd565b604051601f8201601f1916810167ffffffffffffffff81118282101715611648576116486115bd565b604052919050565b60006080828403121561166257600080fd5b82601f83011261167157600080fd5b6040516080810181811067ffffffffffffffff82111715611694576116946115bd565b6040528060808401858111156116a957600080fd5b845b818110156116c35780358352602092830192016116ab565b509195945050505050565b600067ffffffffffffffff8211156116e8576116e86115bd565b5060051b60200190565b6000602080838503121561170557600080fd5b823567ffffffffffffffff81111561171c57600080fd5b8301601f8101851361172d57600080fd5b803561174061173b826116ce565b61161f565b81815260059190911b8201830190838101908783111561175f57600080fd5b928401925b8284101561177d57833582529284019290840190611764565b979650505050505050565b60006040828403121561179a57600080fd5b82601f8301126117a957600080fd5b6117b16115d3565b8060408401858111156117c357600080fd5b845b818110156117dd5780358452602093840193016117c5565b509095945050505050565b600060a082840312156117fa57600080fd5b82601f83011261180957600080fd5b6118116115fc565b8060a08401858111156117c357600080fd5b600080610120838503121561183757600080fd5b823591506118488460208501611544565b90509250929050565b60006060828403121561186357600080fd5b82601f83011261187257600080fd5b6040516060810181811067ffffffffffffffff82111715611895576118956115bd565b6040528060608401858111156116a957600080fd5b6001600160a01b038116811461135957600080fd5b6000602082840312156118d157600080fd5b813561153d816118aa565b805160ff811681146118ed57600080fd5b919050565b6000806000806080858703121561190857600080fd5b611911856118dc565b935061191f602086016118dc565b925061192d604086016118dc565b915061193b606086016118dc565b905092959194509250565b6000806040838503121561195957600080fd5b8251611964816118aa565b6020840151909250611975816118aa565b809150509250929050565b60006020828403121561199257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156119ea5781600019048211156119d0576119d0611999565b808516156119dd57918102915b93841c93908002906119b4565b509250929050565b600082611a0157506001610c63565b81611a0e57506000610c63565b8160018114611a245760028114611a2e57611a4a565b6001915050610c63565b60ff841115611a3f57611a3f611999565b50506001821b610c63565b5060208310610133831016604e8410600b8410161715611a6d575081810a610c63565b611a7783836119af565b8060001904821115611a8b57611a8b611999565b029392505050565b600061153d60ff8416836119f2565b60008060408385031215611ab557600080fd5b505080516020909101519092909150565b80820180821115610c6357610c63611999565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611b0157600080fd5b61153d826118dc565b60ff86811682528581166020830152841660408201526060810183905260a08101611b38608083018461158d565b9695505050505050565b600060408284031215611b5457600080fd5b611b5c6115d3565b9050815181526020820151602082015292915050565b600082601f830112611b8357600080fd5b611b8b6115d3565b806040840185811115611b9d57600080fd5b845b818110156117dd578051845260209384019301611b9f565b600060808284031215611bc957600080fd5b611bd16115d3565b9050611bdd8383611b72565b8152611bec8360408401611b72565b602082015292915050565b60006020808385031215611c0a57600080fd5b825167ffffffffffffffff80821115611c2257600080fd5b908401906101e08287031215611c3757600080fd5b611c3f6115fc565b611c498784611b42565b81526040611c5988828601611bb7565b85830152611c6a8860c08601611bb7565b81830152611c7c886101408601611bb7565b60608301526101c084015183811115611c9457600080fd5b80850194505087601f850112611ca957600080fd5b83519250611cb961173b846116ce565b83815260069390931b84018501928581019089851115611cd857600080fd5b948601945b84861015611cfe57611cef8a87611b42565b82529482019490860190611cdd565b60808401525090979650505050505050565b8060005b6002811015611470578151845260209384019390910190600101611d14565b611d3e828251611d10565b6020810151611d506040840182611d10565b505050565b6000610140610100808785378181850152506103208301611d83828501875180518252602090810151910152565b6020915081860151611d99610180860182611d33565b50604080870151611dae610200870182611d33565b506060870151611dc2610280870182611d33565b5060808701516101e06103008701528051928390528301916000906103408701905b80831015611e1557611e0182865180518252602090810151910152565b938501936001929092019190830190611de4565b50868103610120880152610bda81896114ef565b600060208284031215611e3b57600080fd5b8151801515811461153d57600080fd5b60808101818360005b6004811015611e73578151835260209283019290910190600101611e54565b50505092915050565b815160009082906020808601845b83811015611ea657815185529382019390820190600101611e8a565b50929695505050505050565b6000825160005b81811015611ed35760208186018101518583015201611eb9565b506000920191825250919050565b600082611efe57634e487b7160e01b600052601260045260246000fd5b500690565b60408101818360005b6002811015611e73578151835260209283019290910190600101611f0c565b60a08101818360005b6005811015611e73578151835260209283019290910190600101611f34565b81810381811115610c6357610c63611999565b8082028115828204841417610c6357610c63611999565b60608101818360005b6003811015611e73578151835260209283019290910190600101611f86565b600060018201611fb757611fb7611999565b506001019056fea26469706673582212205431a276c14fca8e4226f4ebbf769fa289bd826bb9e16fac2bac60fd4a2fbf2a64736f6c63430008140033a26469706673582212206484fc599df835f97ba2cea4fdf350f1ccfce49d3bec03c15c4fe629995840e464736f6c63430008140033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063363448731461003b578063683f3dc31461006b575b600080fd5b61004e6100493660046100f8565b610085565b6040516001600160a01b0390911681526020015b60405180910390f35b610073600a81565b60405160ff9091168152602001610062565b6000808686868686604051610099906100cf565b6100a7959493929190610165565b604051809103906000f0801580156100c3573d6000803e3d6000fd5b50979650505050505050565b612264806101bc83390190565b80356001600160a01b03811681146100f357600080fd5b919050565b600080600080600060a0868803121561011057600080fd5b610119866100dc565b9450610127602087016100dc565b9350610135604087016100dc565b9250610143606087016100dc565b915060808601356002811061015757600080fd5b809150509295509295909350565b6001600160a01b038681168252858116602083015284811660408301528316606082015260a08101600283106101ab57634e487b7160e01b600052602160045260246000fd5b826080830152969550505050505056fe6101006040526040516200226438038062002264833981016040819052620000279162000124565b816001600160a01b0381166200005757604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006281620000b7565b506001600160a01b0380861660a05284811660c05283166080528060018111156200009157620000916200019b565b60e0816001811115620000a857620000a86200019b565b815250505050505050620001b1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146200011f57600080fd5b919050565b600080600080600060a086880312156200013d57600080fd5b620001488662000107565b9450620001586020870162000107565b9350620001686040870162000107565b9250620001786060870162000107565b91506080860151600281106200018d57600080fd5b809150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e051611ff462000270600039600081816101cc0152610ac201526000818161016a0152610a240152600081816102000152610b600152600081816102ef0152818161035a015281816103e40152818161046a01528181610500015281816105880152818161071b0152818161082e015281816109050152818161099001528181610dbd01528181610e0e01528181610eb001528181610f4b0152818161106d015281816110fa01526112080152611ff46000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c8063683f3dc3116100b85780639cfced971161007c5780639cfced97146102d7578063a1175279146102ea578063b1a263d314610311578063bea140b314610324578063d13181b814610337578063f2fde38b1461034057600080fd5b8063683f3dc314610285578063715018a61461029f5780637a38d18f146102a95780638763d0c4146102b25780638da5cb5b146102c657600080fd5b80633d6528a1116100ff5780633d6528a1146102225780633dfb88b21461023957806358bfc3791461024c5780635bb939951461025f57806362a361bb1461027257600080fd5b8063023650801461013c57806313fb89321461016557806324fab879146101a4578063295a5212146101c75780632b7ac3f3146101fb575b600080fd5b61014f61014a3660046114cd565b610353565b60405161015c919061152a565b60405180910390f35b61018c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161015c565b6101b76101b2366004611556565b6108fd565b604051901515815260200161015c565b6101ee7f000000000000000000000000000000000000000000000000000000000000000081565b60405161015c91906115af565b61018c7f000000000000000000000000000000000000000000000000000000000000000081565b61022b60025481565b60405190815260200161015c565b61022b610247366004611650565b610be8565b61022b61025a3660046116f2565b610c69565b61022b61026d3660046114cd565b610d03565b61022b610280366004611788565b610d28565b61028d600a81565b60405160ff909116815260200161015c565b6102a7610d62565b005b61022b60015481565b6000546101b790600160a01b900460ff1681565b6000546001600160a01b031661018c565b61022b6102e53660046117e8565b610d76565b61018c7f000000000000000000000000000000000000000000000000000000000000000081565b6102a761031f366004611823565b610db0565b61022b610332366004611851565b6112df565b61022b60035481565b6102a761034e3660046118bf565b611319565b60606000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ac98e5df6040518163ffffffff1660e01b8152600401608060405180830381865afa1580156103b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103da91906118f2565b50925092505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bc14ee2b6040518163ffffffff1660e01b81526004016040805180830381865afa15801561043f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104639190611946565b91505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638aa0ba926040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ea9190611980565b905060006104f9856005611a93565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634f367f0f6040518163ffffffff1660e01b81526004016040805180830381865afa15801561055b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057f9190611aa2565b915091506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634909229f6040518163ffffffff1660e01b81526004016040805180830381865afa1580156105e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106079190611aa2565b90925090506000610618868e611ac6565b9050838111156106255750825b6040805160098082526101408201909252906020820161012080368337019050509a50848b60008151811061065c5761065c611ad9565b60209081029190910101526106718284611ac6565b8b60018151811061068457610684611ad9565b6020908102919091010152604051631b9b8aa760e01b815260ff8a1660048201526001600160a01b03891690631b9b8aa790602401602060405180830381865afa1580156106d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106fa9190611980565b8b60028151811061070d5761070d611ad9565b6020026020010181815250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637028bb0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079b9190611aef565b60ff168b6003815181106107b1576107b1611ad9565b602002602001018181525050808b6004815181106107d1576107d1611ad9565b6020026020010181815250508c8b6005815181106107f1576107f1611ad9565b602002602001018181525050868b60068151811061081157610811611ad9565b60209081029190910101526003541561082c576003546108ae565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c17268d96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561088a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ae9190611980565b8b6007815181106108c1576108c1611ad9565b6020026020010181815250508b8b6008815181106108e1576108e1611ad9565b6020026020010181815250505050505050505050505092915050565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ac98e5df6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610961573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098591906118f2565b9350935093505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bc14ee2b6040518163ffffffff1660e01b81526004016040805180830381865afa1580156109eb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0f9190611946565b5090506000610a1e8989610353565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d88ff4f5846001600160a01b031663652c76e46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab39190611aef565b8787610ac08b6005611a93565b7f00000000000000000000000000000000000000000000000000000000000000006040518663ffffffff1660e01b8152600401610b01959493929190611b0a565b600060405180830381865afa158015610b1e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b469190810190611bf7565b60405163352a4d1560e01b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063352a4d1590610b99908b9085908790600401611d55565b602060405180830381865afa158015610bb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bda9190611e29565b9a9950505050505050505050565b60405163248f667760e01b815260009073e0398f7dfac494c530f6404afeac8669abed26799063248f667790610c22908590600401611e4b565b602060405180830381865af4158015610c3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c639190611980565b92915050565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600283604051602001610c9f9190611e7c565b60408051601f1981840301815290829052610cb991611eb2565b602060405180830381855afa158015610cd6573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610cf99190611980565b610c639190611ee1565b6000610d0d6114af565b83815260208101839052610d2081610d28565b949350505050565b6040516314d2f97b60e11b81526000907307490eba00dc4aca6721d052fa4c5002aa077233906329a5f2f690610c22908590600401611f03565b610d6a61135c565b610d746000611389565b565b604051630926f44b60e31b815260009073fd77833f10a29c76a6a0ede235eb651d744d0e2f90634937a25890610c22908590600401611f2b565b610db861135c565b610de17f00000000000000000000000000000000000000000000000000000000000000006113d9565b600054600160a01b900460ff1615610e0c5760405163a7f0397560e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e33b13a06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8e9190611e29565b610eab5760405163e5fe9e1560e01b815260040160405180910390fd5b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ac98e5df6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610f0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3091906118f2565b5092509250506000826005610f459190611a93565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bc14ee2b6040518163ffffffff1660e01b81526004016040805180830381865afa158015610fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fca9190611946565b604051631b9b8aa760e01b815260ff86166004820152909250600091506001600160a01b03831690631b9b8aa790602401602060405180830381865afa158015611018573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103c9190611980565b90508060000361105f5760405163c0b868a560e01b815260040160405180910390fd5b6001546000036111d75760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c17268d96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ed9190611980565b90508060038190555060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634f367f0f6040518163ffffffff1660e01b81526004016040805180830381865afa158015611155573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111799190611aa2565b9150600090506111898683611ee1565b6002839055905081156111d357806000036111bb5785600260008282546111b09190611f53565b909155506111d39050565b80600260008282546111cd9190611f53565b90915550505b5050505b6111e460025488886108fd565b6112045760405160016268f24f60e01b0319815260040160405180910390fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634f367f0f6040518163ffffffff1660e01b81526004016040805180830381865afa158015611263573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112879190611aa2565b915050600060025411156112ad5783600260008282546112a79190611f53565b90915550505b6112d58860025460015460016112c39190611ac6565b6112cd9088611f66565b841115611476565b5050505050505050565b6040516304b98e1d60e31b815260009073bb0e724ce02e5e7edd31e632dc6e59f229a1126d906325cc70e890610c22908590600401611f7d565b61132161135c565b6001600160a01b03811661135057604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b61135981611389565b50565b6000546001600160a01b03163314610d745760405163118cdaa760e01b8152336004820152602401611347565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080826001600160a01b0316634909229f6040518163ffffffff1660e01b81526004016040805180830381865afa158015611419573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143d9190611aa2565b9092509050600061144e8342611f53565b905081811161147057604051635c3017c560e11b815260040160405180910390fd5b50505050565b60038390556000805460ff60a01b1916600160a01b83151502178155600283905560018054916114a583611fa5565b9190505550505050565b60405180604001604052806002906020820280368337509192915050565b600080604083850312156114e057600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b8381101561151f57815187529582019590820190600101611503565b509495945050505050565b60208152600061153d60208301846114ef565b9392505050565b806101008101831015610c6357600080fd5b6000806000610140848603121561156c57600080fd5b83359250602084013591506115848560408601611544565b90509250925092565b600281106115ab57634e487b7160e01b600052602160045260246000fd5b9052565b60208101610c63828461158d565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156115f6576115f66115bd565b60405290565b60405160a0810167ffffffffffffffff811182821017156115f6576115f66115bd565b604051601f8201601f1916810167ffffffffffffffff81118282101715611648576116486115bd565b604052919050565b60006080828403121561166257600080fd5b82601f83011261167157600080fd5b6040516080810181811067ffffffffffffffff82111715611694576116946115bd565b6040528060808401858111156116a957600080fd5b845b818110156116c35780358352602092830192016116ab565b509195945050505050565b600067ffffffffffffffff8211156116e8576116e86115bd565b5060051b60200190565b6000602080838503121561170557600080fd5b823567ffffffffffffffff81111561171c57600080fd5b8301601f8101851361172d57600080fd5b803561174061173b826116ce565b61161f565b81815260059190911b8201830190838101908783111561175f57600080fd5b928401925b8284101561177d57833582529284019290840190611764565b979650505050505050565b60006040828403121561179a57600080fd5b82601f8301126117a957600080fd5b6117b16115d3565b8060408401858111156117c357600080fd5b845b818110156117dd5780358452602093840193016117c5565b509095945050505050565b600060a082840312156117fa57600080fd5b82601f83011261180957600080fd5b6118116115fc565b8060a08401858111156117c357600080fd5b600080610120838503121561183757600080fd5b823591506118488460208501611544565b90509250929050565b60006060828403121561186357600080fd5b82601f83011261187257600080fd5b6040516060810181811067ffffffffffffffff82111715611895576118956115bd565b6040528060608401858111156116a957600080fd5b6001600160a01b038116811461135957600080fd5b6000602082840312156118d157600080fd5b813561153d816118aa565b805160ff811681146118ed57600080fd5b919050565b6000806000806080858703121561190857600080fd5b611911856118dc565b935061191f602086016118dc565b925061192d604086016118dc565b915061193b606086016118dc565b905092959194509250565b6000806040838503121561195957600080fd5b8251611964816118aa565b6020840151909250611975816118aa565b809150509250929050565b60006020828403121561199257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156119ea5781600019048211156119d0576119d0611999565b808516156119dd57918102915b93841c93908002906119b4565b509250929050565b600082611a0157506001610c63565b81611a0e57506000610c63565b8160018114611a245760028114611a2e57611a4a565b6001915050610c63565b60ff841115611a3f57611a3f611999565b50506001821b610c63565b5060208310610133831016604e8410600b8410161715611a6d575081810a610c63565b611a7783836119af565b8060001904821115611a8b57611a8b611999565b029392505050565b600061153d60ff8416836119f2565b60008060408385031215611ab557600080fd5b505080516020909101519092909150565b80820180821115610c6357610c63611999565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611b0157600080fd5b61153d826118dc565b60ff86811682528581166020830152841660408201526060810183905260a08101611b38608083018461158d565b9695505050505050565b600060408284031215611b5457600080fd5b611b5c6115d3565b9050815181526020820151602082015292915050565b600082601f830112611b8357600080fd5b611b8b6115d3565b806040840185811115611b9d57600080fd5b845b818110156117dd578051845260209384019301611b9f565b600060808284031215611bc957600080fd5b611bd16115d3565b9050611bdd8383611b72565b8152611bec8360408401611b72565b602082015292915050565b60006020808385031215611c0a57600080fd5b825167ffffffffffffffff80821115611c2257600080fd5b908401906101e08287031215611c3757600080fd5b611c3f6115fc565b611c498784611b42565b81526040611c5988828601611bb7565b85830152611c6a8860c08601611bb7565b81830152611c7c886101408601611bb7565b60608301526101c084015183811115611c9457600080fd5b80850194505087601f850112611ca957600080fd5b83519250611cb961173b846116ce565b83815260069390931b84018501928581019089851115611cd857600080fd5b948601945b84861015611cfe57611cef8a87611b42565b82529482019490860190611cdd565b60808401525090979650505050505050565b8060005b6002811015611470578151845260209384019390910190600101611d14565b611d3e828251611d10565b6020810151611d506040840182611d10565b505050565b6000610140610100808785378181850152506103208301611d83828501875180518252602090810151910152565b6020915081860151611d99610180860182611d33565b50604080870151611dae610200870182611d33565b506060870151611dc2610280870182611d33565b5060808701516101e06103008701528051928390528301916000906103408701905b80831015611e1557611e0182865180518252602090810151910152565b938501936001929092019190830190611de4565b50868103610120880152610bda81896114ef565b600060208284031215611e3b57600080fd5b8151801515811461153d57600080fd5b60808101818360005b6004811015611e73578151835260209283019290910190600101611e54565b50505092915050565b815160009082906020808601845b83811015611ea657815185529382019390820190600101611e8a565b50929695505050505050565b6000825160005b81811015611ed35760208186018101518583015201611eb9565b506000920191825250919050565b600082611efe57634e487b7160e01b600052601260045260246000fd5b500690565b60408101818360005b6002811015611e73578151835260209283019290910190600101611f0c565b60a08101818360005b6005811015611e73578151835260209283019290910190600101611f34565b81810381811115610c6357610c63611999565b8082028115828204841417610c6357610c63611999565b60608101818360005b6003811015611e73578151835260209283019290910190600101611f86565b600060018201611fb757611fb7611999565b506001019056fea26469706673582212205431a276c14fca8e4226f4ebbf769fa289bd826bb9e16fac2bac60fd4a2fbf2a64736f6c63430008140033a26469706673582212206484fc599df835f97ba2cea4fdf350f1ccfce49d3bec03c15c4fe629995840e464736f6c63430008140033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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.