OP Sepolia Testnet

Contract

0xad844a9567ada5996FFC0D2DeC78b3767a1c0501

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
0xad844a95...67a1c0501
 Contract Creation0 ETH
210951552024-12-12 8:40:5035 days ago1733992850
0xad844a95...67a1c0501
 Contract Creation0 ETH
210947322024-12-12 8:26:4435 days ago1733992004
0xad844a95...67a1c0501
 Contract Creation0 ETH
210947322024-12-12 8:26:4435 days ago1733992004
0xad844a95...67a1c0501
 Contract Creation0 ETH
207943232024-12-05 9:33:0642 days ago1733391186
0xad844a95...67a1c0501
 Contract Creation0 ETH
207943232024-12-05 9:33:0642 days ago1733391186
0xad844a95...67a1c0501
 Contract Creation0 ETH
207912742024-12-05 7:51:2842 days ago1733385088
0xad844a95...67a1c0501
 Contract Creation0 ETH
207912742024-12-05 7:51:2842 days ago1733385088
0xad844a95...67a1c0501
 Contract Creation0 ETH
206998612024-12-03 5:04:2244 days ago1733202262
0xad844a95...67a1c0501
 Contract Creation0 ETH
206998612024-12-03 5:04:2244 days ago1733202262
0xad844a95...67a1c0501
 Contract Creation0 ETH
206718462024-12-02 13:30:3245 days ago1733146232
0xad844a95...67a1c0501
 Contract Creation0 ETH
206718462024-12-02 13:30:3245 days ago1733146232
0xad844a95...67a1c0501
 Contract Creation0 ETH
206708392024-12-02 12:56:5845 days ago1733144218
0xad844a95...67a1c0501
 Contract Creation0 ETH
206708392024-12-02 12:56:5845 days ago1733144218
0xad844a95...67a1c0501
 Contract Creation0 ETH
198760942024-11-14 3:25:2863 days ago1731554728
0xad844a95...67a1c0501
 Contract Creation0 ETH
198760942024-11-14 3:25:2863 days ago1731554728
0xad844a95...67a1c0501
 Contract Creation0 ETH
198723692024-11-14 1:21:1863 days ago1731547278
0xad844a95...67a1c0501
 Contract Creation0 ETH
198723692024-11-14 1:21:1863 days ago1731547278
0xad844a95...67a1c0501
 Contract Creation0 ETH
198707402024-11-14 0:27:0063 days ago1731544020
0xad844a95...67a1c0501
 Contract Creation0 ETH
198707402024-11-14 0:27:0063 days ago1731544020
0xad844a95...67a1c0501
 Contract Creation0 ETH
198554262024-11-13 15:56:3264 days ago1731513392
0xad844a95...67a1c0501
 Contract Creation0 ETH
198554262024-11-13 15:56:3264 days ago1731513392
0xad844a95...67a1c0501
 Contract Creation0 ETH
198540502024-11-13 15:10:4064 days ago1731510640
0xad844a95...67a1c0501
 Contract Creation0 ETH
198540502024-11-13 15:10:4064 days ago1731510640
0xad844a95...67a1c0501
 Contract Creation0 ETH
198539692024-11-13 15:07:5864 days ago1731510478
0xad844a95...67a1c0501
 Contract Creation0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PollFactory

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 23 : PollFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { IMACI } from "./interfaces/IMACI.sol";
import { AccQueue } from "./trees/AccQueue.sol";
import { AccQueueQuinaryMaci } from "./trees/AccQueueQuinaryMaci.sol";
import { Params } from "./utilities/Params.sol";
import { DomainObjs } from "./utilities/DomainObjs.sol";
import { Poll } from "./Poll.sol";
import { IPollFactory } from "./interfaces/IPollFactory.sol";

/// @title PollFactory
/// @notice A factory contract which deploys Poll contracts. It allows the MACI contract
/// size to stay within the limit set by EIP-170.
contract PollFactory is Params, DomainObjs, IPollFactory {
  /// @notice The PollFactory constructor
  // solhint-disable-next-line no-empty-blocks
  constructor() payable {}

  /// @inheritdoc IPollFactory
  function deploy(
    uint256 _duration,
    TreeDepths calldata _treeDepths,
    PubKey calldata _coordinatorPubKey,
    address _maci,
    uint256 _emptyBallotRoot
  ) public virtual returns (address pollAddr) {
    /// @notice deploy a new AccQueue contract to store messages
    AccQueue messageAq = new AccQueueQuinaryMaci(_treeDepths.messageTreeSubDepth);

    /// @notice the smart contracts that a Poll would interact with
    ExtContracts memory extContracts = ExtContracts({ maci: IMACI(_maci), messageAq: messageAq });

    // deploy the poll
    Poll poll = new Poll(_duration, _treeDepths, _coordinatorPubKey, extContracts, _emptyBallotRoot);

    // Make the Poll contract own the messageAq contract, so only it can
    // run enqueue/merge
    messageAq.transferOwnership(address(poll));

    // init Poll
    poll.init();

    pollAddr = address(poll);
  }
}

File 2 of 23 : 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 23 : 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 23 : BabyJubJub.sol
// @note This code was taken from
// https://github.com/yondonfu/sol-baby-jubjub/blob/master/contracts/CurveBabyJubJub.sol
// Thanks to yondonfu for the code
// Implementation cited on baby-jubjub's paper
// https://eips.ethereum.org/EIPS/eip-2494#implementation

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

library CurveBabyJubJub {
  // Curve parameters
  // E: 168700x^2 + y^2 = 1 + 168696x^2y^2
  // A = 168700
  uint256 public constant A = 0x292FC;
  // D = 168696
  uint256 public constant D = 0x292F8;
  // Prime Q = 21888242871839275222246405745257275088548364400416034343698204186575808495617
  uint256 public constant Q = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001;

  /**
   * @dev Add 2 points on baby jubjub curve
   * Formula for adding 2 points on a twisted Edwards curve:
   * x3 = (x1y2 + y1x2) / (1 + dx1x2y1y2)
   * y3 = (y1y2 - ax1x2) / (1 - dx1x2y1y2)
   */
  function pointAdd(uint256 _x1, uint256 _y1, uint256 _x2, uint256 _y2) internal view returns (uint256 x3, uint256 y3) {
    if (_x1 == 0 && _y1 == 0) {
      return (_x2, _y2);
    }

    if (_x2 == 0 && _y1 == 0) {
      return (_x1, _y1);
    }

    uint256 x1x2 = mulmod(_x1, _x2, Q);
    uint256 y1y2 = mulmod(_y1, _y2, Q);
    uint256 dx1x2y1y2 = mulmod(D, mulmod(x1x2, y1y2, Q), Q);
    uint256 x3Num = addmod(mulmod(_x1, _y2, Q), mulmod(_y1, _x2, Q), Q);
    uint256 y3Num = submod(y1y2, mulmod(A, x1x2, Q), Q);

    x3 = mulmod(x3Num, inverse(addmod(1, dx1x2y1y2, Q)), Q);
    y3 = mulmod(y3Num, inverse(submod(1, dx1x2y1y2, Q)), Q);
  }

  /**
   * @dev Double a point on baby jubjub curve
   * Doubling can be performed with the same formula as addition
   */
  function pointDouble(uint256 _x1, uint256 _y1) internal view returns (uint256 x2, uint256 y2) {
    return pointAdd(_x1, _y1, _x1, _y1);
  }

  /**
   * @dev Multiply a point on baby jubjub curve by a scalar
   * Use the double and add algorithm
   */
  function pointMul(uint256 _x1, uint256 _y1, uint256 _d) internal view returns (uint256 x2, uint256 y2) {
    uint256 remaining = _d;

    uint256 px = _x1;
    uint256 py = _y1;
    uint256 ax = 0;
    uint256 ay = 0;

    while (remaining != 0) {
      if ((remaining & 1) != 0) {
        // Binary digit is 1 so add
        (ax, ay) = pointAdd(ax, ay, px, py);
      }

      (px, py) = pointDouble(px, py);

      remaining = remaining / 2;
    }

    x2 = ax;
    y2 = ay;
  }

  /**
   * @dev Check if a given point is on the curve
   * (168700x^2 + y^2) - (1 + 168696x^2y^2) == 0
   */
  function isOnCurve(uint256 _x, uint256 _y) internal pure returns (bool) {
    uint256 xSq = mulmod(_x, _x, Q);
    uint256 ySq = mulmod(_y, _y, Q);
    uint256 lhs = addmod(mulmod(A, xSq, Q), ySq, Q);
    uint256 rhs = addmod(1, mulmod(mulmod(D, xSq, Q), ySq, Q), Q);
    return submod(lhs, rhs, Q) == 0;
  }

  /**
   * @dev Perform modular subtraction
   */
  function submod(uint256 _a, uint256 _b, uint256 _mod) internal pure returns (uint256) {
    uint256 aNN = _a;

    if (_a <= _b) {
      aNN += _mod;
    }

    return addmod(aNN - _b, 0, _mod);
  }

  /**
   * @dev Compute modular inverse of a number
   */
  function inverse(uint256 _a) internal view returns (uint256) {
    // We can use Euler's theorem instead of the extended Euclidean algorithm
    // Since m = Q and Q is prime we have: a^-1 = a^(m - 2) (mod m)
    return expmod(_a, Q - 2, Q);
  }

  /**
   * @dev Helper function to call the bigModExp precompile
   */
  function expmod(uint256 _b, uint256 _e, uint256 _m) internal view returns (uint256 o) {
    assembly {
      let memPtr := mload(0x40)
      mstore(memPtr, 0x20) // Length of base _b
      mstore(add(memPtr, 0x20), 0x20) // Length of exponent _e
      mstore(add(memPtr, 0x40), 0x20) // Length of modulus _m
      mstore(add(memPtr, 0x60), _b) // Base _b
      mstore(add(memPtr, 0x80), _e) // Exponent _e
      mstore(add(memPtr, 0xa0), _m) // Modulus _m

      // The bigModExp precompile is at 0x05
      let success := staticcall(gas(), 0x05, memPtr, 0xc0, memPtr, 0x20)
      switch success
      case 0 {
        revert(0x0, 0x0)
      }
      default {
        o := mload(memPtr)
      }
    }
  }
}

File 5 of 23 : Hasher.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { SnarkConstants } from "./SnarkConstants.sol";
import { PoseidonT3 } from "./PoseidonT3.sol";
import { PoseidonT4 } from "./PoseidonT4.sol";
import { PoseidonT5 } from "./PoseidonT5.sol";
import { PoseidonT6 } from "./PoseidonT6.sol";

/// @notice A SHA256 hash function for any number of input elements, and Poseidon hash
/// functions for 2, 3, 4, 5, and 12 input elements.
contract Hasher is SnarkConstants {
  /// @notice Computes the SHA256 hash of an array of uint256 elements.
  /// @param array The array of uint256 elements.
  /// @return result The SHA256 hash of the array.
  function sha256Hash(uint256[] memory array) public pure returns (uint256 result) {
    result = uint256(sha256(abi.encodePacked(array))) % SNARK_SCALAR_FIELD;
  }

  /// @notice Computes the Poseidon hash of two uint256 elements.
  /// @param array An array of two uint256 elements.
  /// @return result The Poseidon hash of the two elements.
  function hash2(uint256[2] memory array) public pure returns (uint256 result) {
    result = PoseidonT3.poseidon(array);
  }

  /// @notice Computes the Poseidon hash of three uint256 elements.
  /// @param array An array of three uint256 elements.
  /// @return result The Poseidon hash of the three elements.
  function hash3(uint256[3] memory array) public pure returns (uint256 result) {
    result = PoseidonT4.poseidon(array);
  }

  /// @notice Computes the Poseidon hash of four uint256 elements.
  /// @param array An array of four uint256 elements.
  /// @return result The Poseidon hash of the four elements.
  function hash4(uint256[4] memory array) public pure returns (uint256 result) {
    result = PoseidonT5.poseidon(array);
  }

  /// @notice Computes the Poseidon hash of five uint256 elements.
  /// @param array An array of five uint256 elements.
  /// @return result The Poseidon hash of the five elements.
  function hash5(uint256[5] memory array) public pure returns (uint256 result) {
    result = PoseidonT6.poseidon(array);
  }

  /// @notice Computes the Poseidon hash of two uint256 elements.
  /// @param left the first element to hash.
  /// @param right the second element to hash.
  /// @return result The Poseidon hash of the two elements.
  function hashLeftRight(uint256 left, uint256 right) public pure returns (uint256 result) {
    uint256[2] memory input;
    input[0] = left;
    input[1] = right;
    result = hash2(input);
  }
}

File 6 of 23 : 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 7 of 23 : 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 8 of 23 : 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 9 of 23 : 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 10 of 23 : 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 11 of 23 : 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 12 of 23 : 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 13 of 23 : IMACI.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/// @title IMACI
/// @notice MACI interface
interface IMACI {
  /// @notice Get the depth of the state tree
  /// @return The depth of the state tree
  function stateTreeDepth() external view returns (uint8);

  /// @notice Return the main root of the StateAq contract
  /// @return The Merkle root
  function getStateTreeRoot() external view returns (uint256);

  /// @notice Get the number of signups
  /// @return numsignUps The number of signups
  function numSignUps() external view returns (uint256);
}

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

import { Params } from "../utilities/Params.sol";
import { DomainObjs } from "../utilities/DomainObjs.sol";

/// @title IPollFactory
/// @notice PollFactory interface
interface IPollFactory {
  /// @notice Deploy a new Poll contract and AccQueue contract for messages.
  /// @param _duration The duration of the poll
  /// @param _treeDepths The depths of the merkle trees
  /// @param _coordinatorPubKey The coordinator's public key
  /// @param _maci The MACI contract interface reference
  /// @param _emptyBallotRoot The root of the empty ballot tree
  /// @return The deployed Poll contract
  function deploy(
    uint256 _duration,
    Params.TreeDepths memory _treeDepths,
    DomainObjs.PubKey memory _coordinatorPubKey,
    address _maci,
    uint256 _emptyBallotRoot
  ) external returns (address);
}

File 16 of 23 : Poll.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { Params } from "./utilities/Params.sol";
import { SnarkCommon } from "./crypto/SnarkCommon.sol";
import { IPoll } from "./interfaces/IPoll.sol";
import { Utilities } from "./utilities/Utilities.sol";
import { CurveBabyJubJub } from "./crypto/BabyJubJub.sol";

/// @title Poll
/// @notice A Poll contract allows voters to submit encrypted messages
/// which can be either votes or key change messages.
/// @dev Do not deploy this directly. Use PollFactory.deploy() which performs some
/// checks on the Poll constructor arguments.
contract Poll is Params, Utilities, SnarkCommon, IPoll {
  /// @notice Whether the Poll has been initialized
  bool internal isInit;

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

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

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

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

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

  /// @notice The root of the empty ballot tree at a given voteOptionTree depth
  uint256 public immutable emptyBallotRoot;

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

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

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

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

  /// @notice The actual depth of the state tree
  /// to be used as public input for the circuit
  uint8 public actualStateTreeDepth;

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

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

  /// @notice The max number of messages
  uint256 public immutable maxMessages;

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

  error VotingPeriodOver();
  error VotingPeriodNotOver();
  error PollAlreadyInit();
  error TooManyMessages();
  error InvalidPubKey();
  error StateAlreadyMerged();
  error InvalidBatchLength();

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

  /// @notice Each MACI instance can have multiple Polls.
  /// When a Poll is deployed, its voting period starts immediately.
  /// @param _duration The duration of the voting period, in seconds
  /// @param _treeDepths The depths of the merkle trees
  /// @param _coordinatorPubKey The coordinator's public key
  /// @param _extContracts The external contracts
  constructor(
    uint256 _duration,
    TreeDepths memory _treeDepths,
    PubKey memory _coordinatorPubKey,
    ExtContracts memory _extContracts,
    uint256 _emptyBallotRoot
  ) payable {
    // check that the coordinator public key is valid
    if (!CurveBabyJubJub.isOnCurve(_coordinatorPubKey.x, _coordinatorPubKey.y)) {
      revert InvalidPubKey();
    }

    // store the pub key as object then calculate the hash
    coordinatorPubKey = _coordinatorPubKey;
    // we hash it ourselves to ensure we store the correct value
    coordinatorPubKeyHash = hashLeftRight(_coordinatorPubKey.x, _coordinatorPubKey.y);
    // store the external contracts to interact with
    extContracts = _extContracts;
    // store duration of the poll
    duration = _duration;
    // store tree depth
    treeDepths = _treeDepths;
    // Record the current timestamp
    deployTime = block.timestamp;
    // store the empty ballot root
    emptyBallotRoot = _emptyBallotRoot;
    // store max messages
    maxMessages = TREE_ARITY ** _treeDepths.messageTreeDepth;
  }

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

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

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

    unchecked {
      numMessages++;
    }

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

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

    emit PublishMessage(_message, _padKey);
  }

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

    // check if the public key is on the curve
    if (!CurveBabyJubJub.isOnCurve(_encPubKey.x, _encPubKey.y)) {
      revert InvalidPubKey();
    }

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

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

    emit PublishMessage(_message, _encPubKey);
  }

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

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

      unchecked {
        i++;
      }
    }
  }

  /// @inheritdoc IPoll
  function mergeMaciState() public isAfterVotingDeadline {
    // This function can only be called once per Poll after the voting
    // deadline
    if (stateMerged) revert StateAlreadyMerged();

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

    uint256 _mergedStateRoot = extContracts.maci.getStateTreeRoot();
    mergedStateRoot = _mergedStateRoot;

    // Set currentSbCommitment
    uint256[3] memory sb;
    sb[0] = _mergedStateRoot;
    sb[1] = emptyBallotRoot;
    sb[2] = uint256(0);

    currentSbCommitment = hash3(sb);

    // get number of signups and cache in a var for later use
    uint256 _numSignups = extContracts.maci.numSignUps();
    numSignups = _numSignups;

    // dynamically determine the actual depth of the state tree
    uint8 depth = 1;
    while (uint40(1 << depth) < _numSignups) {
      depth++;
    }

    actualStateTreeDepth = depth;

    emit MergeMaciState(_mergedStateRoot, _numSignups);
  }

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

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

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

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

File 17 of 23 : AccQueue.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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

/// @title AccQueue
/// @notice This contract defines a Merkle tree where each leaf insertion only updates a
/// subtree. To obtain the main tree root, the contract owner must merge the
/// subtrees together. Merging subtrees requires at least 2 operations:
/// mergeSubRoots(), and merge(). To get around the gas limit,
/// the mergeSubRoots() can be performed in multiple transactions.
abstract contract AccQueue is Ownable(msg.sender), Hasher {
  // The maximum tree depth
  uint256 public constant MAX_DEPTH = 32;

  /// @notice A Queue is a 2D array of Merkle roots and indices which represents nodes
  /// in a Merkle tree while it is progressively updated.
  struct Queue {
    /// @notice IMPORTANT: the following declares an array of b elements of type T: T[b]
    /// And the following declares an array of b elements of type T[a]: T[a][b]
    /// As such, the following declares an array of MAX_DEPTH+1 arrays of
    /// uint256[4] arrays, **not the other way round**:
    uint256[4][MAX_DEPTH + 1] levels;
    uint256[MAX_DEPTH + 1] indices;
  }

  // The depth of each subtree
  uint256 internal immutable subDepth;

  // The number of elements per hash operation. Should be either 2 (for
  // binary trees) or 5 (quinary trees). The limit is 5 because that is the
  // maximum supported number of inputs for the EVM implementation of the
  // Poseidon hash function
  uint256 internal immutable hashLength;

  // hashLength ** subDepth
  uint256 internal immutable subTreeCapacity;

  // True hashLength == 2, false if hashLength == 5
  bool internal isBinary;

  // The index of the current subtree. e.g. the first subtree has index 0, the
  // second has 1, and so on
  uint256 internal currentSubtreeIndex;

  // Tracks the current subtree.
  Queue internal leafQueue;

  // Tracks the smallest tree of subroots
  Queue internal subRootQueue;

  // Subtree roots
  mapping(uint256 => uint256) internal subRoots;

  // Merged roots
  uint256[MAX_DEPTH + 1] internal mainRoots;

  // Whether the subtrees have been merged
  bool public subTreesMerged;

  // Whether entire merkle tree has been merged
  bool public treeMerged;

  // The root of the shortest possible tree which fits all current subtree
  // roots
  uint256 internal smallSRTroot;

  // Tracks the next subroot to queue
  uint256 internal nextSubRootIndex;

  // The number of leaves inserted across all subtrees so far
  uint256 public numLeaves;

  /// @notice custom errors
  error SubDepthCannotBeZero();
  error SubdepthTooLarge(uint256 _subDepth, uint256 max);
  error InvalidHashLength();
  error DepthCannotBeZero();
  error SubTreesAlreadyMerged();
  error NothingToMerge();
  error SubTreesNotMerged();
  error DepthTooLarge(uint256 _depth, uint256 max);
  error DepthTooSmall(uint256 _depth, uint256 min);
  error InvalidIndex(uint256 _index);
  error InvalidLevel();

  /// @notice Create a new AccQueue
  /// @param _subDepth The depth of each subtree.
  /// @param _hashLength The number of leaves per node (2 or 5).
  constructor(uint256 _subDepth, uint256 _hashLength) payable {
    /// validation
    if (_subDepth == 0) revert SubDepthCannotBeZero();
    if (_subDepth > MAX_DEPTH) revert SubdepthTooLarge(_subDepth, MAX_DEPTH);
    if (_hashLength != 2 && _hashLength != 5) revert InvalidHashLength();

    isBinary = _hashLength == 2;
    subDepth = _subDepth;
    hashLength = _hashLength;
    subTreeCapacity = _hashLength ** _subDepth;
  }

  /// @notice Hash the contents of the specified level and the specified leaf.
  /// This is a virtual function as the hash function which the overriding
  /// contract uses will be either hashLeftRight or hash5, which require
  /// different input array lengths.
  /// @param _level The level to hash.
  /// @param _leaf The leaf include with the level.
  /// @return _hash The hash of the level and leaf.
  // solhint-disable-next-line no-empty-blocks
  function hashLevel(uint256 _level, uint256 _leaf) internal virtual returns (uint256 _hash) {}

  /// @notice Hash the contents of the specified level and the specified leaf.
  /// This is a virtual function as the hash function which the overriding
  /// contract uses will be either hashLeftRight or hash5, which require
  /// different input array lengths.
  /// @param _level The level to hash.
  /// @param _leaf The leaf include with the level.
  /// @return _hash The hash of the level and leaf.
  // solhint-disable-next-line no-empty-blocks
  function hashLevelLeaf(uint256 _level, uint256 _leaf) public view virtual returns (uint256 _hash) {}

  /// @notice Returns the zero leaf at a specified level.
  /// This is a virtual function as the hash function which the overriding
  /// contract uses will be either hashLeftRight or hash5, which will produce
  /// different zero values (e.g. hashLeftRight(0, 0) vs
  /// hash5([0, 0, 0, 0, 0]). Moreover, the zero value may be a
  /// nothing-up-my-sleeve value.
  /// @param _level The level at which to return the zero leaf.
  /// @return zero The zero leaf at the specified level.
  // solhint-disable-next-line no-empty-blocks
  function getZero(uint256 _level) internal virtual returns (uint256 zero) {}

  /// @notice Add a leaf to the queue for the current subtree.
  /// @param _leaf The leaf to add.
  /// @return leafIndex The index of the leaf in the queue.
  function enqueue(uint256 _leaf) public onlyOwner returns (uint256 leafIndex) {
    leafIndex = numLeaves;
    // Recursively queue the leaf
    _enqueue(_leaf, 0);

    // Update the leaf counter
    numLeaves = leafIndex + 1;

    // Now that a new leaf has been added, mainRoots and smallSRTroot are
    // obsolete
    delete mainRoots;
    delete smallSRTroot;
    subTreesMerged = false;

    // If a subtree is full
    if (numLeaves % subTreeCapacity == 0) {
      // Store the subroot
      subRoots[currentSubtreeIndex] = leafQueue.levels[subDepth][0];

      // Increment the index
      currentSubtreeIndex++;

      // Delete ancillary data
      delete leafQueue.levels[subDepth][0];
      delete leafQueue.indices;
    }
  }

  /// @notice Updates the queue at a given level and hashes any subroots
  /// that need to be hashed.
  /// @param _leaf The leaf to add.
  /// @param _level The level at which to queue the leaf.
  function _enqueue(uint256 _leaf, uint256 _level) internal {
    if (_level > subDepth) {
      revert InvalidLevel();
    }

    while (true) {
      uint256 n = leafQueue.indices[_level];

      if (n != hashLength - 1) {
        // Just store the leaf
        leafQueue.levels[_level][n] = _leaf;

        if (_level != subDepth) {
          // Update the index
          leafQueue.indices[_level]++;
        }

        return;
      }

      // Hash the leaves to next level
      _leaf = hashLevel(_level, _leaf);

      // Reset the index for this level
      delete leafQueue.indices[_level];

      // Queue the hash of the leaves into to the next level
      _level++;
    }
  }

  /// @notice Fill any empty leaves of the current subtree with zeros and store the
  /// resulting subroot.
  function fill() public onlyOwner {
    if (numLeaves % subTreeCapacity == 0) {
      // If the subtree is completely empty, then the subroot is a
      // precalculated zero value
      subRoots[currentSubtreeIndex] = getZero(subDepth);
    } else {
      // Otherwise, fill the rest of the subtree with zeros
      _fill(0);

      // Store the subroot
      subRoots[currentSubtreeIndex] = leafQueue.levels[subDepth][0];

      // Reset the subtree data
      delete leafQueue.levels;

      // Reset the merged roots
      delete mainRoots;
    }

    // Increment the subtree index
    uint256 curr = currentSubtreeIndex + 1;
    currentSubtreeIndex = curr;

    // Update the number of leaves
    numLeaves = curr * subTreeCapacity;

    // Reset the subroot tree root now that it is obsolete
    delete smallSRTroot;

    subTreesMerged = false;
  }

  /// @notice A function that queues zeros to the specified level, hashes,
  /// the level, and enqueues the hash to the next level.
  /// @param _level The level at which to queue zeros.
  // solhint-disable-next-line no-empty-blocks
  function _fill(uint256 _level) internal virtual {}

  /// Insert a subtree. Used for batch enqueues.
  function insertSubTree(uint256 _subRoot) public onlyOwner {
    subRoots[currentSubtreeIndex] = _subRoot;

    // Increment the subtree index
    currentSubtreeIndex++;

    // Update the number of leaves
    numLeaves += subTreeCapacity;

    // Reset the subroot tree root now that it is obsolete
    delete smallSRTroot;

    subTreesMerged = false;
  }

  /// @notice Calculate the lowest possible height of a tree with
  /// all the subroots merged together.
  /// @return depth The lowest possible height of a tree with all the
  function calcMinHeight() public view returns (uint256 depth) {
    depth = 1;
    while (true) {
      if (hashLength ** depth >= currentSubtreeIndex) {
        break;
      }
      depth++;
    }
  }

  /// @notice Merge all subtrees to form the shortest possible tree.
  /// This function can be called either once to merge all subtrees in a
  /// single transaction, or multiple times to do the same in multiple
  /// transactions.
  /// @param _numSrQueueOps The number of times this function will call
  ///                       queueSubRoot(), up to the maximum number of times
  ///                       necessary. If it is set to 0, it will call
  ///                       queueSubRoot() as many times as is necessary. Set
  ///                       this to a low number and call this function
  ///                       multiple times if there are many subroots to
  ///                       merge, or a single transaction could run out of
  ///                       gas.
  function mergeSubRoots(uint256 _numSrQueueOps) public onlyOwner {
    // This function can only be called once unless a new subtree is created
    if (subTreesMerged) revert SubTreesAlreadyMerged();

    // There must be subtrees to merge
    if (numLeaves == 0) revert NothingToMerge();

    // Fill any empty leaves in the current subtree with zeros only if the
    // current subtree is not full
    if (numLeaves % subTreeCapacity != 0) {
      fill();
    }

    // If there is only 1 subtree, use its root
    if (currentSubtreeIndex == 1) {
      smallSRTroot = getSubRoot(0);
      subTreesMerged = true;
      return;
    }

    uint256 depth = calcMinHeight();

    uint256 queueOpsPerformed = 0;
    for (uint256 i = nextSubRootIndex; i < currentSubtreeIndex; i++) {
      if (_numSrQueueOps != 0 && queueOpsPerformed == _numSrQueueOps) {
        // If the limit is not 0, stop if the limit has been reached
        return;
      }

      // Queue the next subroot
      queueSubRoot(getSubRoot(nextSubRootIndex), 0, depth);

      // Increment the next subroot counter
      nextSubRootIndex++;

      // Increment the ops counter
      queueOpsPerformed++;
    }

    // The height of the tree of subroots
    uint256 m = hashLength ** depth;

    // Queue zeroes to fill out the SRT
    if (nextSubRootIndex == currentSubtreeIndex) {
      uint256 z = getZero(subDepth);
      for (uint256 i = currentSubtreeIndex; i < m; i++) {
        queueSubRoot(z, 0, depth);
      }
    }

    // Store the smallest main root
    smallSRTroot = subRootQueue.levels[depth][0];
    subTreesMerged = true;
  }

  /// @notice Queues a subroot into the subroot tree.
  /// @param _leaf The value to queue.
  /// @param _level The level at which to queue _leaf.
  /// @param _maxDepth The depth of the tree.
  function queueSubRoot(uint256 _leaf, uint256 _level, uint256 _maxDepth) internal {
    if (_level > _maxDepth) {
      return;
    }

    uint256 n = subRootQueue.indices[_level];

    if (n != hashLength - 1) {
      // Just store the leaf
      subRootQueue.levels[_level][n] = _leaf;
      subRootQueue.indices[_level]++;
    } else {
      // Hash the elements in this level and queue it in the next level
      uint256 hashed;
      if (isBinary) {
        uint256[2] memory inputs;
        inputs[0] = subRootQueue.levels[_level][0];
        inputs[1] = _leaf;
        hashed = hash2(inputs);
      } else {
        uint256[5] memory inputs;
        for (uint8 i = 0; i < n; i++) {
          inputs[i] = subRootQueue.levels[_level][i];
        }
        inputs[n] = _leaf;
        hashed = hash5(inputs);
      }

      // TODO: change recursion to a while loop
      // Recurse
      delete subRootQueue.indices[_level];
      queueSubRoot(hashed, _level + 1, _maxDepth);
    }
  }

  /// @notice Merge all subtrees to form a main tree with a desired depth.
  /// @param _depth The depth of the main tree. It must fit all the leaves or
  ///               this function will revert.
  /// @return root The root of the main tree.
  function merge(uint256 _depth) public onlyOwner returns (uint256 root) {
    // The tree depth must be more than 0
    if (_depth == 0) revert DepthCannotBeZero();

    // Ensure that the subtrees have been merged
    if (!subTreesMerged) revert SubTreesNotMerged();

    // Check the depth
    if (_depth > MAX_DEPTH) revert DepthTooLarge(_depth, MAX_DEPTH);

    // Calculate the SRT depth
    uint256 srtDepth = subDepth;
    while (true) {
      if (hashLength ** srtDepth >= numLeaves) {
        break;
      }
      srtDepth++;
    }

    if (_depth < srtDepth) revert DepthTooSmall(_depth, srtDepth);

    // If the depth is the same as the SRT depth, just use the SRT root
    if (_depth == srtDepth) {
      mainRoots[_depth] = smallSRTroot;
      treeMerged = true;
      return smallSRTroot;
    } else {
      root = smallSRTroot;

      // Calculate the main root

      for (uint256 i = srtDepth; i < _depth; i++) {
        uint256 z = getZero(i);

        if (isBinary) {
          uint256[2] memory inputs;
          inputs[0] = root;
          inputs[1] = z;
          root = hash2(inputs);
        } else {
          uint256[5] memory inputs;
          inputs[0] = root;
          inputs[1] = z;
          inputs[2] = z;
          inputs[3] = z;
          inputs[4] = z;
          root = hash5(inputs);
        }
      }

      mainRoots[_depth] = root;
      treeMerged = true;
    }
  }

  /// @notice Returns the subroot at the specified index. Reverts if the index refers
  /// to a subtree which has not been filled yet.
  /// @param _index The subroot index.
  /// @return subRoot The subroot at the specified index.
  function getSubRoot(uint256 _index) public view returns (uint256 subRoot) {
    if (currentSubtreeIndex <= _index) revert InvalidIndex(_index);
    subRoot = subRoots[_index];
  }

  /// @notice Returns the subroot tree (SRT) root. Its value must first be computed
  /// using mergeSubRoots.
  /// @return smallSubTreeRoot The SRT root.
  function getSmallSRTroot() public view returns (uint256 smallSubTreeRoot) {
    if (!subTreesMerged) revert SubTreesNotMerged();
    smallSubTreeRoot = smallSRTroot;
  }

  /// @notice Return the merged Merkle root of all the leaves at a desired depth.
  /// @dev merge() or merged(_depth) must be called first.
  /// @param _depth The depth of the main tree. It must first be computed
  ///               using mergeSubRoots() and merge().
  /// @return mainRoot The root of the main tree.
  function getMainRoot(uint256 _depth) public view returns (uint256 mainRoot) {
    if (hashLength ** _depth < numLeaves) revert DepthTooSmall(_depth, numLeaves);

    mainRoot = mainRoots[_depth];
  }

  /// @notice Get the next subroot index and the current subtree index.
  function getSrIndices() public view returns (uint256 next, uint256 current) {
    next = nextSubRootIndex;
    current = currentSubtreeIndex;
  }
}

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

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

/// @title AccQueueQuinary
/// @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.
/// @dev This contract is for a quinary tree (5 leaves per node)
abstract contract AccQueueQuinary is AccQueue {
  /// @notice Create a new AccQueueQuinary instance
  constructor(uint256 _subDepth) AccQueue(_subDepth, 5) {}

  /// @notice Hash the contents of the specified level and the specified leaf.
  /// @dev it also frees up storage slots to refund gas.
  /// @param _level The level to hash.
  /// @param _leaf The leaf include with the level.
  /// @return hashed The hash of the level and leaf.
  function hashLevel(uint256 _level, uint256 _leaf) internal override returns (uint256 hashed) {
    uint256[5] memory inputs;
    inputs[0] = leafQueue.levels[_level][0];
    inputs[1] = leafQueue.levels[_level][1];
    inputs[2] = leafQueue.levels[_level][2];
    inputs[3] = leafQueue.levels[_level][3];
    inputs[4] = _leaf;
    hashed = hash5(inputs);

    // Free up storage slots to refund gas. Note that using a loop here
    // would result in lower gas savings.
    delete leafQueue.levels[_level];
  }

  /// @notice Hash the contents of the specified level and the specified leaf.
  /// @param _level The level to hash.
  /// @param _leaf The leaf include with the level.
  /// @return hashed The hash of the level and leaf.
  function hashLevelLeaf(uint256 _level, uint256 _leaf) public view override returns (uint256 hashed) {
    uint256[5] memory inputs;
    inputs[0] = leafQueue.levels[_level][0];
    inputs[1] = leafQueue.levels[_level][1];
    inputs[2] = leafQueue.levels[_level][2];
    inputs[3] = leafQueue.levels[_level][3];
    inputs[4] = _leaf;
    hashed = hash5(inputs);
  }

  /// @notice An internal function which fills a subtree
  /// @param _level The level at which to fill the subtree
  function _fill(uint256 _level) internal override {
    while (_level < subDepth) {
      uint256 n = leafQueue.indices[_level];

      if (n != 0) {
        // Fill the subtree level with zeros and hash the level
        uint256 hashed;

        uint256[5] memory inputs;
        uint256 z = getZero(_level);
        uint8 i = 0;
        for (; i < n; i++) {
          inputs[i] = leafQueue.levels[_level][i];
        }

        for (; i < hashLength; i++) {
          inputs[i] = z;
        }
        hashed = hash5(inputs);

        // Update the subtree from the next level onwards with the new leaf
        _enqueue(hashed, _level + 1);
      }

      // Reset the current level
      delete leafQueue.indices[_level];

      _level++;
    }
  }
}

File 19 of 23 : AccQueueQuinaryMaci.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { MerkleZeros as MerkleQuinaryMaci } from "./zeros/MerkleQuinaryMaci.sol";
import { AccQueueQuinary } from "./AccQueueQuinary.sol";

/// @title AccQueueQuinaryMaci
/// @notice This contract extends AccQueueQuinary and MerkleQuinaryMaci
/// @dev This contract is used for creating a
/// Merkle tree with quinary (5 leaves per node) structure
contract AccQueueQuinaryMaci is AccQueueQuinary, MerkleQuinaryMaci {
  /// @notice Constructor for creating AccQueueQuinaryMaci contract
  /// @param _subDepth The depth of each subtree
  constructor(uint256 _subDepth) AccQueueQuinary(_subDepth) {}

  /// @notice Returns the zero leaf at a specified level
  /// @param _level The level at which to return the zero leaf
  /// @return zero The zero leaf at the specified level
  function getZero(uint256 _level) internal view override returns (uint256 zero) {
    zero = zeros[_level];
  }
}

File 20 of 23 : MerkleQuinaryMaci.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

abstract contract MerkleZeros {
  uint256[33] internal zeros;

  // Quinary tree zeros (Keccak hash of 'Maci')
  constructor() {
    zeros[0] = uint256(8370432830353022751713833565135785980866757267633941821328460903436894336785);
    zeros[1] = uint256(12915444503621073454579416579430905206970714557680052030066757042249102605307);
    zeros[2] = uint256(15825388848727206932541662858173052318786639683743459477657913288690190505308);
    zeros[3] = uint256(20672917177817295069558894035958266756825295443848082659014905185716743537191);
    zeros[4] = uint256(448586013948167251740855715259393055429962470693972912240018559200278204556);
    zeros[5] = uint256(3228865992178886480410396198366133115832717015233640381802715479176981303177);
    zeros[6] = uint256(19116532419590876304532847271428641103751206695152259493043279205958851263600);
    zeros[7] = uint256(13531983203936271379763604150672239370281863210813769735936250692178889682484);
    zeros[8] = uint256(8276490051100115441938424474671329955897359239518198952109759468777824929104);
    zeros[9] = uint256(1234816188709792521426066175633785051600533236493067959807265450339481920006);
    zeros[10] = uint256(14253963034950198848796956783804665963745244419038717333683296599064556174281);
    zeros[11] = uint256(6367560368479067766970398112009211893636892126125767203198799843543931913172);
    zeros[12] = uint256(9086778412328290069463938062555298073857321633960448227011862356090607842391);
    zeros[13] = uint256(1440983698234119608650157588008070947531139377294971527360643096251396484622);
    zeros[14] = uint256(3957599085599383799297196095384587366602816424699353871878382158004571037876);
    zeros[15] = uint256(2874250189355749385170216620368454832544508482778847425177457138604069991955);
    zeros[16] = uint256(21009179226085449764156117702096359546848859855915028677582017987249294772778);
    zeros[17] = uint256(11639371146919469643603772238908032714588430905217730187804009793768292270213);
    zeros[18] = uint256(6279313411277883478350325643881386249374023631847602720184182017599127173896);
    zeros[19] = uint256(21059196126634383551994255775761712285020874549906884292741523421591865338509);
    zeros[20] = uint256(9444544622817172574621750245792527383369133221167610044960147559319164808325);
    zeros[21] = uint256(5374570219497355452080912323548395721574511162814862844226178635172695078543);
    zeros[22] = uint256(4155904241440251764630449308160227499466701168124519106689866311729092343061);
    zeros[23] = uint256(15881609944326576145786405158479503217901875433072026818450276983706463215155);
    zeros[24] = uint256(20831546672064137588434602157208687297579005252478070660473540633558666587287);
    zeros[25] = uint256(3209071488384365842993449718919243416332014108747571544339190291353564426179);
    zeros[26] = uint256(10030934989297780221224272248227257782450689603145083016739151821673604746295);
    zeros[27] = uint256(16504852316033851373501270056537918974469380446508638487151124538300880427080);
    zeros[28] = uint256(5226137093551352657015038416264755428944140743893702595442932837011856178457);
    zeros[29] = uint256(18779994066356991319291039019820482828679702085087990978933303018673869446075);
    zeros[30] = uint256(12037506572124351893114409509086276299115869080424687624451184925646292710978);
    zeros[31] = uint256(12049750997011422639258622747494178076018128204515149991024639355149614767606);
    zeros[32] = uint256(3171463916443906096008599541392648187002297410622977814790586531203175805057);
  }
}

File 21 of 23 : 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 23 : Params.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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

/// @title Params
/// @notice This contracts contains a number of structures
/// which are to be passed as parameters to Poll contracts.
/// This way we can reduce the number of parameters
/// and avoid a stack too deep error during compilation.
contract Params {
  /// @notice A struct holding the depths of the merkle trees
  struct TreeDepths {
    uint8 intStateTreeDepth;
    uint8 messageTreeSubDepth;
    uint8 messageTreeDepth;
    uint8 voteOptionTreeDepth;
  }

  /// @notice A struct holding the external contracts
  /// that are to be passed to a Poll contract on
  /// deployment
  struct ExtContracts {
    IMACI maci;
    AccQueue messageAq;
  }
}

File 23 of 23 : Utilities.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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

/// @title Utilities
/// @notice An utility contract that can be used to:
/// * hash a state leaf
/// * pad and hash a MACI message
/// * hash a MACI message and an encryption public key
contract Utilities is SnarkConstants, DomainObjs, Hasher {
  /// @notice custom errors
  error InvalidMessage();

  /// @notice An utility function used to hash a state leaf
  /// @param _stateLeaf the state leaf to be hashed
  /// @return ciphertext The hash of the state leaf
  function hashStateLeaf(StateLeaf memory _stateLeaf) public pure returns (uint256 ciphertext) {
    uint256[4] memory plaintext;
    plaintext[0] = _stateLeaf.pubKey.x;
    plaintext[1] = _stateLeaf.pubKey.y;
    plaintext[2] = _stateLeaf.voiceCreditBalance;
    plaintext[3] = _stateLeaf.timestamp;

    ciphertext = hash4(plaintext);
  }

  /// @notice An utility function used to pad and hash a MACI message
  /// @param dataToPad the data to be padded
  /// @return message The padded message
  /// @return padKey The padding public key
  /// @return msgHash The hash of the padded message and encryption key
  function padAndHashMessage(
    uint256[2] memory dataToPad
  ) public pure returns (Message memory message, PubKey memory padKey, uint256 msgHash) {
    // add data and pad it to 10 elements (automatically cause it's the default value)
    uint256[10] memory dat;
    dat[0] = dataToPad[0];
    dat[1] = dataToPad[1];

    padKey = PubKey(PAD_PUBKEY_X, PAD_PUBKEY_Y);
    message = Message({ data: dat });
    msgHash = hashMessageAndEncPubKey(message, padKey);
  }

  /// @notice An utility function used to hash a MACI message and an encryption public key
  /// @param _message the message to be hashed
  /// @param _encPubKey the encryption public key to be hashed
  /// @return msgHash The hash of the message and the encryption public key
  function hashMessageAndEncPubKey(
    Message memory _message,
    PubKey memory _encPubKey
  ) public pure returns (uint256 msgHash) {
    if (_message.data.length != 10) {
      revert InvalidMessage();
    }

    uint256[5] memory n;
    n[0] = _message.data[0];
    n[1] = _message.data[1];
    n[2] = _message.data[2];
    n[3] = _message.data[3];
    n[4] = _message.data[4];

    uint256[5] memory m;
    m[0] = _message.data[5];
    m[1] = _message.data[6];
    m[2] = _message.data[7];
    m[3] = _message.data[8];
    m[4] = _message.data[9];

    msgHash = hash4([hash5(n), hash5(m), _encPubKey.x, _encPubKey.y]);
  }
}

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

Contract ABI

[{"inputs":[],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"MESSAGE_DATA_LENGTH","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"},{"components":[{"internalType":"uint8","name":"intStateTreeDepth","type":"uint8"},{"internalType":"uint8","name":"messageTreeSubDepth","type":"uint8"},{"internalType":"uint8","name":"messageTreeDepth","type":"uint8"},{"internalType":"uint8","name":"voteOptionTreeDepth","type":"uint8"}],"internalType":"struct Params.TreeDepths","name":"_treeDepths","type":"tuple"},{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct DomainObjs.PubKey","name":"_coordinatorPubKey","type":"tuple"},{"internalType":"address","name":"_maci","type":"address"},{"internalType":"uint256","name":"_emptyBallotRoot","type":"uint256"}],"name":"deploy","outputs":[{"internalType":"address","name":"pollAddr","type":"address"}],"stateMutability":"nonpayable","type":"function"}]

60806040526147be806100136000396000f3fe60806040523480156200001157600080fd5b50600436106200003a5760003560e01c8063683f3dc3146200003f57806370f7b361146200005f575b600080fd5b62000048600a81565b60405160ff90911681526020015b60405180910390f35b620000766200007036600462000229565b6200008f565b6040516001600160a01b03909116815260200162000056565b600080620000a46040870160208801620002bf565b604051620000b2906200020d565b60ff9091168152602001604051809103906000f080158015620000d9573d6000803e3d6000fd5b50905060006040518060400160405280866001600160a01b03168152602001836001600160a01b03168152509050600088888884886040516200011c906200021b565b6200012c959493929190620002e4565b604051809103906000f08015801562000149573d6000803e3d6000fd5b5060405163f2fde38b60e01b81526001600160a01b0380831660048301529192509084169063f2fde38b90602401600060405180830381600087803b1580156200019257600080fd5b505af1158015620001a7573d6000803e3d6000fd5b50505050806001600160a01b031663e1c7392a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015620001e757600080fd5b505af1158015620001fc573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6122dc806200038183390190565b61212c806200265d83390190565b60008060008060008587036101208112156200024457600080fd5b863595506080601f19820112156200025b57600080fd5b6020870194506040609f19820112156200027457600080fd5b5060a08601925060e08601356001600160a01b03811681146200029657600080fd5b94979396509194610100013592915050565b803560ff81168114620002ba57600080fd5b919050565b600060208284031215620002d257600080fd5b620002dd82620002a8565b9392505050565b858152610140810160ff620002f987620002a8565b16602083015260ff6200030f60208801620002a8565b16604083015260ff6200032560408801620002a8565b16606083015260ff6200033b60608801620002a8565b166080830152843560a083015260209485013560c083015283516001600160a01b0390811660e08401529390940151909216610100830152610120909101529291505056fe60e06040523480156200001157600080fd5b50604051620022dc380380620022dc83398101604081905262000034916200063d565b8080600533806200006057604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6200006b81620005ed565b50816000036200008e5760405163682e504160e11b815260040160405180910390fd5b6020821115620000bc57604051637ccdcc9760e11b8152600481018390526020602482015260440162000057565b80600214158015620000cf575080600514155b15620000ee57604051636f7b6c0360e01b815260040160405180910390fd5b6000805460ff60a01b191660028314600160a01b02179055608082905260a08190526200011c82826200076c565b60c05250507f12817f4161f2f5ded33f26c55735a77e80e4f8975483c8c2704745128417f7116101725550507f1c8de1edeabc24fc4c1595acaabb70be9b70f351d58c6fa338e1e9a994413bfb610173557f22fcda488c14b34fc60eb073fbe92fe10793e2ab14682e0f057332ddbef3d55c610174557f2db474db7c7212646cb15c6177d87be30711e6c04f1139d8e495ef1d1d998227610175557efde404053ec39a19f6ac347121a2264815dda84f910a388cb372e967a5d08c610176557f0723792ffab6ec6cfb3ece1509b9b4fb07e5bdb2299d1538e6e1db916f90cf89610177557f2a4392ec4e3d1811cd6a950cc865ee6f2342910a6551c5dce38cb995576c7c70610178557f1dead4c14f75e9d8449c80b648dcd4694c2ee50da2ba16e5e438f0d77ab02e34610179557f124c53ce0953fffb7ab5e3c143df6cd48ba747d3959fcb8086405d763ed5455061017a557f02bae19605746a8cd3f0927b2c01630f36f4d1bab9216ca839833e7ff6efa20661017b557f1f8375099becf17173d457d0d07bfb74c7067df1143b5ad987046e8e66817bc961017c557f0e13e954d61bb3fa3b03e7d136ca909b610fa2ca4443d920d94d16684f2b83d461017d557f1416ef2fc4f88fcfc4f9eb12f8e214b1c3e31c6c10ece9cfa51f078a3bbf345761017e557f032f915ff71e198a7955d2697249f40fb94c65812ed24e670c9700f52fdf6e0e61017f557f08bfebf4b3ddb0f8c51dd40193f5996da9f3d799ee0d8beb6be4038132df60b4610180557f065ac498cf4a5acaeb3b6cee826da9f834c961fa39feff6ae925b90dff79b613610181557f2e72c628101a93201b912a3e3fe96d39b0a9076ec39b7935a015c59bb32b8a2a610182557f19bba68e7b9da1e6ec42e52d7ab2adaf3b6a5521b1a454ec70f62e0ab702c085610183557f0de1f72745a5af2a34cac412e00eb6c8b5db1f3b52fa1bff88076c2726b83b08610184557f2e8f152603b2fac10d6a14c841327c23c502537367ccb1e42fab9a3bd9db2a8d610185557f14e16c3e0dcfd7e621a32627ebf37f6c0afb4467d34c7b7aeffded11769dec85610186557f0be1e62127948b4805c85a1d836574f0892ca6473fcde98f3fd1781248a9768f610187557f0930288fbd7c849197c8372f1dd8f9087f8a03f09b9cd904a469c15ef6b1b515610188557f231cac34e215e3f404d2fcfb79e0705deeb3d40978f0ee31072f6cbc1b579e33610189557f2e0e3cd2718ac7199b81dc14e841de40a9536b7ffe95fa1fc9c6b799e43e2c9761018a557f0718452506f0a232e98966d84b1a4675a66bd80263a2dc58bdac873825752fc361018b557f162d4ed998307d6e132edbf5c11f62f53d4636aa10cb3c2244c2bf5577168c3761018c557f247d6a5544a8f295a894ae77c7efcdcbf52e3bf4e5d0c0d2f40557a61d44984861018d557f0b8de3868471f109e91670daca698dba917d1c5535821f33aa9598d1db8e3d1961018e557f29851997020f527c92e20f030d232b81d334144a641e6a8866b46dd925005bbb61018f557f1a9cfcbe29a2b6503a03049727c0bca3111afd62f2836f392080321d1b4ef642610190557f1aa3ead91fa89cc1d6cb1d0eb76a27190c6abfdd3265d6d0a1e5c58feddaddf6610191557f0702fc26a7d367e6677efefd95204a7e00144c2fc7dbc2a581aa00d99f51f0816101925562000781565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156200065057600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600181815b80851115620006ae57816000190482111562000692576200069262000657565b80851615620006a057918102915b93841c939080029062000672565b509250929050565b600082620006c75750600162000766565b81620006d65750600062000766565b8160018114620006ef5760028114620006fa576200071a565b600191505062000766565b60ff8411156200070e576200070e62000657565b50506001821b62000766565b5060208310610133831016604e8410600b84101617156200073f575081810a62000766565b6200074b83836200066d565b806000190482111562000762576200076262000657565b0290505b92915050565b60006200077a8383620006b6565b9392505050565b60805160a05160c051611aad6200082f600039600081816103ea01528181610a2501528181610ac201528181610c7f0152610d820152600081816103230152818161056e015281816106e401528181610bb401528181610ec301528181611037015261129801526000818161041a0152818161047b0152818161054401528181610bed01528181610cb801528181610d0201528181610e6401528181610f1a01526111d30152611aad6000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c806381d6a24a116100c3578063c00bdbcc1161007c578063c00bdbcc146102b8578063c15da65b146102cb578063d9c55ce1146102de578063dda89a6e146102e6578063e93fb4d4146102f0578063f2fde38b1461030357600080fd5b806381d6a24a146102455780638da5cb5b146102615780639cfced971461027c578063a27154ba1461028f578063b6a64acd14610297578063bea140b3146102a557600080fd5b806358bfc3791161011557806358bfc379146101cc5780635bb93995146101df5780635bf1fa4d146101f257806362a361bb1461020557806369e7c58614610218578063715018a61461023b57600080fd5b80631b9b8aa71461015d5780631ffc735d1461018357806324a47aeb146101965780633bfa6fce146101a95780633dfb88b2146101b15780633e1a8cc1146101c4575b600080fd5b61017061016b3660046114ba565b610316565b6040519081526020015b60405180910390f35b6101706101913660046114ba565b610399565b6101706101a43660046114ba565b6104c7565b6101706106d8565b6101706101bf36600461151a565b610723565b6101706107a4565b6101706101da366004611598565b6107d3565b6101706101ed36600461163e565b61086d565b61017061020036600461163e565b610892565b610170610213366004611660565b610931565b61016e5461022b90610100900460ff1681565b604051901515815260200161017a565b61024361096b565b005b610170546001546040805192835260208301919091520161017a565b6000546040516001600160a01b03909116815260200161017a565b61017061028a3660046116bb565b61097f565b610170602081565b61016e5461022b9060ff1681565b6101706102b3366004611714565b6109b9565b6102436102c63660046114ba565b6109f3565b6102436102d93660046114ba565b610a6f565b610243610c75565b6101706101715481565b6101706102fe3660046114ba565b610dbf565b61024361031136600461176d565b610dfa565b61017154600090610347837f0000000000000000000000000000000000000000000000000000000000000000611897565b101561037d5761017154604051627289df60e61b8152610374918491600401918252602082015260400190565b60405180910390fd5b61014d8260218110610391576103916118a3565b015492915050565b60006103a3610e35565b50610171546103b3826000610e62565b6103be8160016118b9565b610171556103cf61014d600061141f565b600061016f5561016e805460ff191690556101715461040f907f0000000000000000000000000000000000000000000000000000000000000000906118cc565b6000036104c25760027f000000000000000000000000000000000000000000000000000000000000000060218110610449576104496118a3565b600402015460018054600090815261014c6020526040812092909255805491610471836118ee565b90915550600290507f0000000000000000000000000000000000000000000000000000000000000000602181106104aa576104aa6118a3565b6004020160008091018190556104c29060869061141f565b919050565b60006104d1610e35565b816000036104f257604051630543d40760e11b815260040160405180910390fd5b61016e5460ff1661051657604051631e596e4360e11b815260040160405180910390fd5b602082111561054257604051632cd31ae960e01b81526004810183905260206024820152604401610374565b7f00000000000000000000000000000000000000000000000000000000000000005b61017154610592827f0000000000000000000000000000000000000000000000000000000000000000611897565b10156105aa57806105a2816118ee565b915050610564565b808310156105d457604051627289df60e61b81526004810184905260248101829052604401610374565b8083036106105761016f5461014d84602181106105f3576105f36118a3565b0155505061016e805461ff00191661010017905561016f54919050565b61016f549150805b838110156106aa57600061062b82610fa3565b600054909150600160a01b900460ff16156106635761064861142e565b8481526020810182905261065b81610931565b945050610697565b61066b61144c565b848152602081018290526040810182905260608101829052608081018290526106938161097f565b9450505b50806106a2816118ee565b915050610618565b508161014d84602181106106c0576106c06118a3565b015561016e805461ff00191661010017905550919050565b60015b600154610708827f0000000000000000000000000000000000000000000000000000000000000000611897565b10156107205780610718816118ee565b9150506106db565b90565b60405163248f667760e01b815260009073e0398f7dfac494c530f6404afeac8669abed26799063248f66779061075d908590600401611907565b602060405180830381865af415801561077a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079e9190611938565b92915050565b61016e5460009060ff166107cb57604051631e596e4360e11b815260040160405180910390fd5b5061016f5490565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016002836040516020016108099190611951565b60408051601f198184030181529082905261082391611987565b602060405180830381855afa158015610840573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906108639190611938565b61079e91906118cc565b600061087761142e565b8381526020810183905261088a81610931565b949350505050565b600061089c61144c565b600284602181106108af576108af6118a3565b60040201548152600284602181106108c9576108c96118a3565b60040201600101548160016020020152600284602181106108ec576108ec6118a3565b600402016002015481600260200201526002846021811061090f5761090f6118a3565b6004020160030154816003602002015282816004602002015261088a8161097f565b6040516314d2f97b60e11b81526000907307490eba00dc4aca6721d052fa4c5002aa077233906329a5f2f69061075d9085906004016119b6565b610973610e35565b61097d6000610fb9565b565b604051630926f44b60e31b815260009073fd77833f10a29c76a6a0ede235eb651d744d0e2f90634937a2589061075d9085906004016119de565b6040516304b98e1d60e31b815260009073bb0e724ce02e5e7edd31e632dc6e59f229a1126d906325cc70e89061075d908590600401611a06565b6109fb610e35565b60018054600090815261014c6020526040812083905581549190610a1e836118ee565b91905055507f00000000000000000000000000000000000000000000000000000000000000006101716000828254610a5691906118b9565b9091555050600061016f555061016e805460ff19169055565b610a77610e35565b61016e5460ff1615610a9c57604051630d36aec160e01b815260040160405180910390fd5b61017154600003610ac0576040516316a0341160e11b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000061017154610aef91906118cc565b15610afc57610afc610c75565b600154600103610b2557610b106000610dbf565b61016f5561016e805460ff1916600117905550565b6000610b2f6106d8565b610170549091506000905b600154811015610bab578315801590610b5257508382145b15610b5d5750505050565b610b74610b6c61017054610dbf565b600085611009565b6101708054906000610b85836118ee565b91905055508180610b95906118ee565b9250508080610ba3906118ee565b915050610b3a565b506000610bd8837f0000000000000000000000000000000000000000000000000000000000000000611897565b90506001546101705403610c41576000610c117f0000000000000000000000000000000000000000000000000000000000000000610fa3565b6001549091505b82811015610c3e57610c2c82600087611009565b80610c36816118ee565b915050610c18565b50505b60a78360218110610c5457610c546118a3565b600402016000015461016f55505061016e805460ff19166001179055505b50565b610c7d610e35565b7f000000000000000000000000000000000000000000000000000000000000000061017154610cac91906118cc565b600003610cf457610cdc7f0000000000000000000000000000000000000000000000000000000000000000610fa3565b600154600090815261014c6020526040902055610d65565b610cfe60006111d1565b60027f000000000000000000000000000000000000000000000000000000000000000060218110610d3157610d316118a3565b6004020154600154600090815261014c6020526040812091909155610d589060029061146a565b610d6561014d600061141f565b60006001546001610d7691906118b9565b60018190559050610da77f000000000000000000000000000000000000000000000000000000000000000082611a2e565b6101715550600061016f5561016e805460ff19169055565b60008160015411610de65760405163042a2e7160e11b815260048101839052602401610374565b50600090815261014c602052604090205490565b610e02610e35565b6001600160a01b038116610e2c57604051631e4fbdf760e01b815260006004820152602401610374565b610c7281610fb9565b6000546001600160a01b0316331461097d5760405163118cdaa760e01b8152336004820152602401610374565b7f0000000000000000000000000000000000000000000000000000000000000000811115610ea35760405163d1459f7960e01b815260040160405180910390fd5b600060868260218110610eb857610eb86118a3565b01549050610ee760017f0000000000000000000000000000000000000000000000000000000000000000611a45565b8114610f6c578260028360218110610f0157610f016118a3565b600402018260048110610f1657610f166118a3565b01557f00000000000000000000000000000000000000000000000000000000000000008214610f675760868260218110610f5257610f526118a3565b018054906000610f61836118ee565b91905055505b505050565b610f76828461133d565b925060868260218110610f8b57610f8b6118a3565b600091015581610f9a816118ee565b92505050610ea3565b60006101728260218110610391576103916118a3565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8082111561101657505050565b600061012b836021811061102c5761102c6118a3565b0154905061105b60017f0000000000000000000000000000000000000000000000000000000000000000611a45565b81146110b9578360a78460218110611075576110756118a3565b60040201826004811061108a5761108a6118a3565b015561012b83602181106110a0576110a06118a3565b0180549060006110af836118ee565b91905055506111cb565b60008054600160a01b900460ff1615611106576110d461142e565b60a785602181106110e7576110e76118a3565b60040201548152602081018690526110fe81610931565b91505061119b565b61110e61144c565b60005b838160ff1610156111755760a7866021811061112f5761112f6118a3565b600402018160ff1660048110611147576111476118a3565b0154828260ff166005811061115e5761115e6118a3565b60200201528061116d81611a58565b915050611111565b5085818460058110611189576111896118a3565b60200201526111978161097f565b9150505b61012b84602181106111af576111af6118a3565b60009101556111c9816111c38660016118b9565b85611009565b505b50505050565b7f0000000000000000000000000000000000000000000000000000000000000000811015610c725760006086826021811061120e5761120e6118a3565b01549050801561131257600061122261144c565b600061122d85610fa3565b905060005b848160ff1610156112965760028660218110611250576112506118a3565b600402018160ff1660048110611268576112686118a3565b0154838260ff166005811061127f5761127f6118a3565b60200201528061128e81611a58565b915050611232565b7f00000000000000000000000000000000000000000000000000000000000000008160ff1610156112ee5781838260ff16600581106112d7576112d76118a3565b6020020152806112e681611a58565b915050611296565b6112f78361097f565b935061130d846113088860016118b9565b610e62565b505050505b60868260218110611325576113256118a3565b600091015581611334816118ee565b925050506111d1565b600061134761144c565b6002846021811061135a5761135a6118a3565b6004020154815260028460218110611374576113746118a3565b6004020160010154816001602002015260028460218110611397576113976118a3565b60040201600201548160026020020152600284602181106113ba576113ba6118a3565b600402016003015481600360200201528281600460200201526113dc8161097f565b9150600284602181106113f1576113f16118a3565b60040201600061141891905060008155600101600081556001016000815560010160009055565b5092915050565b50610c72906021810190611479565b60405180604001604052806002906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b50610c72906084810190611492565b5b8082111561148e576000815560010161147a565b5090565b8082111561148e57600080825560018201819055600282018190556003820155600401611492565b6000602082840312156114cc57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611512576115126114d3565b604052919050565b60006080828403121561152c57600080fd5b82601f83011261153b57600080fd5b6040516080810181811067ffffffffffffffff8211171561155e5761155e6114d3565b60405280608084018581111561157357600080fd5b845b8181101561158d578035835260209283019201611575565b509195945050505050565b600060208083850312156115ab57600080fd5b823567ffffffffffffffff808211156115c357600080fd5b818501915085601f8301126115d757600080fd5b8135818111156115e9576115e96114d3565b8060051b91506115fa8483016114e9565b818152918301840191848101908884111561161457600080fd5b938501935b8385101561163257843582529385019390850190611619565b98975050505050505050565b6000806040838503121561165157600080fd5b50508035926020909101359150565b60006040828403121561167257600080fd5b82601f83011261168157600080fd5b6040516040810181811067ffffffffffffffff821117156116a4576116a46114d3565b806040525080604084018581111561157357600080fd5b600060a082840312156116cd57600080fd5b82601f8301126116dc57600080fd5b60405160a0810181811067ffffffffffffffff821117156116ff576116ff6114d3565b6040528060a084018581111561157357600080fd5b60006060828403121561172657600080fd5b82601f83011261173557600080fd5b6040516060810181811067ffffffffffffffff82111715611758576117586114d3565b60405280606084018581111561157357600080fd5b60006020828403121561177f57600080fd5b81356001600160a01b038116811461179657600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156117ee5781600019048211156117d4576117d461179d565b808516156117e157918102915b93841c93908002906117b8565b509250929050565b6000826118055750600161079e565b816118125750600061079e565b816001811461182857600281146118325761184e565b600191505061079e565b60ff8411156118435761184361179d565b50506001821b61079e565b5060208310610133831016604e8410600b8410161715611871575081810a61079e565b61187b83836117b3565b806000190482111561188f5761188f61179d565b029392505050565b600061179683836117f6565b634e487b7160e01b600052603260045260246000fd5b8082018082111561079e5761079e61179d565b6000826118e957634e487b7160e01b600052601260045260246000fd5b500690565b6000600182016119005761190061179d565b5060010190565b60808101818360005b600481101561192f578151835260209283019290910190600101611910565b50505092915050565b60006020828403121561194a57600080fd5b5051919050565b815160009082906020808601845b8381101561197b5781518552938201939082019060010161195f565b50929695505050505050565b6000825160005b818110156119a8576020818601810151858301520161198e565b506000920191825250919050565b60408101818360005b600281101561192f5781518352602092830192909101906001016119bf565b60a08101818360005b600581101561192f5781518352602092830192909101906001016119e7565b60608101818360005b600381101561192f578151835260209283019290910190600101611a0f565b808202811582820484141761079e5761079e61179d565b8181038181111561079e5761079e61179d565b600060ff821660ff8103611a6e57611a6e61179d565b6001019291505056fea2646970667358221220de48377ebab560ef190138d15ea2cd48ec74d706562bdc76aca8c6093ed43a8e64736f6c634300081400336101206040526040516200212c3803806200212c8339810160408190526200002791620003da565b825160208401516200003a91906200013a565b62000058576040516379fae7af60e01b815260040160405180910390fd5b8251600181905560208401516002819055620000759190620001ef565b6080528151600a80546001600160a01b039283166001600160a01b031991821617909155602080850151600b80549190941692169190911790915560c08690528451600980549287015160408801805160608a015160ff90811663010000000263ff0000001992821662010000029290921663ffff0000199482166101000261ffff199098169190961617959095179190911692909217929092179091554260a05260e0829052516200012a906005620005c8565b61010052506200066f9350505050565b6000806000805160206200210c833981519152848509905060006000805160206200210c833981519152848509905060006000805160206200210c833981519152826000805160206200210c83398151915285620292fc0908905060006000805160206200210c83398151915280846000805160206200210c83398151915287620292f809096001089050620001e182826000805160206200210c83398151915262000218565b159450505050505b92915050565b6000620001fb620002db565b8381526020810183905262000210816200025b565b949350505050565b60008383811162000232576200022f8382620005f6565b90505b8280620002435762000243620005e0565b60006200025186846200060c565b0895945050505050565b6040516314d2f97b60e11b81526000907307490eba00dc4aca6721d052fa4c5002aa077233906329a5f2f6906200029790859060040162000622565b602060405180830381865af4158015620002b5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001e9919062000655565b60405180604001604052806002906020820280368337509192915050565b604080519081016001600160401b03811182821017156200032a57634e487b7160e01b600052604160045260246000fd5b60405290565b604051608081016001600160401b03811182821017156200032a57634e487b7160e01b600052604160045260246000fd5b805160ff811681146200037357600080fd5b919050565b6001600160a01b03811681146200038e57600080fd5b50565b600060408284031215620003a457600080fd5b620003ae620002f9565b90508151620003bd8162000378565b81526020820151620003cf8162000378565b602082015292915050565b6000806000806000858703610140811215620003f557600080fd5b865195506080601f19820112156200040c57600080fd5b6200041662000330565b620004246020890162000361565b8152620004346040890162000361565b6020820152620004476060890162000361565b60408201526200045a6080890162000361565b606082015294506040609f19820112156200047457600080fd5b506200047f620002f9565b60a0870151815260c087015160208201529250620004a18760e0880162000391565b915061012086015190509295509295909350565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156200050c578160001904821115620004f057620004f0620004b5565b80851615620004fe57918102915b93841c9390800290620004d0565b509250929050565b6000826200052557506001620001e9565b816200053457506000620001e9565b81600181146200054d5760028114620005585762000578565b6001915050620001e9565b60ff8411156200056c576200056c620004b5565b50506001821b620001e9565b5060208310610133831016604e8410600b84101617156200059d575081810a620001e9565b620005a98383620004cb565b8060001904821115620005c057620005c0620004b5565b029392505050565b6000620005d960ff84168362000514565b9392505050565b634e487b7160e01b600052601260045260246000fd5b80820180821115620001e957620001e9620004b5565b81810381811115620001e957620001e9620004b5565b60408101818360005b60028110156200064c5781518352602092830192909101906001016200062b565b50505092915050565b6000602082840312156200066857600080fd5b5051919050565b60805160a05160c05160e05161010051611a12620006fa60003960008181610299015261066b01526000818161033a0152610cf6015260008181610270015281816105100152818161062b01528181610ad00152610c0501526000818161024f015281816104e70152818161060201528181610aa70152610bdc015260006103940152611a126000f3fe608060405234801561001057600080fd5b50600436106101d95760003560e01c80637028bb0e11610104578063ac98e5df116100a2578063e1c7392a11610071578063e1c7392a14610490578063e33b13a014610498578063edbfe83f146104b5578063fba630f2146104d757600080fd5b8063ac98e5df146103e4578063bc14ee2b1461043a578063bea140b314610474578063c17268d91461048757600080fd5b80638aa0ba92116100de5780638aa0ba921461038f5780639c971729146103b65780639cfced97146103c9578063a28bc38c146103dc57600080fd5b80637028bb0e1461035c5780637d0a81c8146103695780638a2a3dfb1461037c57600080fd5b80634f367f0f1161017c578063623f54ac1161014b578063623f54ac146102f557806362a361bb14610308578063683f3dc31461031b5780636d582d341461033557600080fd5b80634f367f0f146102bb57806358bfc379146102c65780635bb93995146102d95780635d5909dd146102ec57600080fd5b806331e766a5116101b857806331e766a5146102175780633dfb88b21461023a5780634909229f1461024d5780634966efd61461029457600080fd5b8062329f2f146101de5780630f4cf692146101e857806327bea0da14610204575b600080fd5b6101e66104e0565b005b6101f160065481565b6040519081526020015b60405180910390f35b6101e66102123660046112aa565b6105fb565b600154600254610225919082565b604080519283526020830191909152016101fb565b6101f16102483660046112ed565b6107a5565b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000610225565b6101f17f000000000000000000000000000000000000000000000000000000000000000081565b600754600654610225565b6101f16102d436600461136b565b610826565b6101f16102e7366004611411565b6108ae565b6101f160075481565b6101e6610303366004611433565b6108d3565b6101f16103163660046114fc565b610958565b610323600a81565b60405160ff90911681526020016101fb565b6101f17f000000000000000000000000000000000000000000000000000000000000000081565b6008546103239060ff1681565b6101f16103773660046115a6565b610992565b6101f161038a366004611608565b6109d2565b6101f17f000000000000000000000000000000000000000000000000000000000000000081565b6101e66103c436600461163f565b610aa0565b6101f16103d7366004611658565b610b9b565b6101e6610bd5565b60095461040d9060ff808216916101008104821691620100008204811691630100000090041684565b6040805160ff958616815293851660208501529184169183019190915290911660608201526080016101fb565b600a54600b54610454916001600160a01b03908116911682565b604080516001600160a01b039384168152929091166020830152016101fb565b6101f16104823660046116b1565b610e10565b6101f160055481565b6101e6610e4a565b6004546104a59060ff1681565b60405190151581526020016101fb565b6104c86104c33660046114fc565b610f6d565b6040516101fb93929190611736565b6101f160035481565b600061050c7f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f0000000000000000000000000000000000000000000000000000000000000000811161054e57604051630931513d60e11b815260040160405180910390fd5b600b546009546040516324a47aeb60e01b81526201000090910460ff1660048201526000916001600160a01b0316906324a47aeb906024016020604051808303816000875af11580156105a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c9919061178c565b60405190915081907fc5624680ab5d50c84507f9e0dc2032163de2bda906ab8a661a53dd4d43bd5dc790600090a25050565b60006106277f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f000000000000000000000000000000000000000000000000000000000000000081106106695760405163148fb9a960e31b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000600654106106ab57604051631ec0b2f760e01b815260040160405180910390fd5b6106ba82356020840135611015565b6106d7576040516379fae7af60e01b815260040160405180910390fd5b60068054600101905560006106f58461038a368690038601866117a5565b600b54604051631ffc735d60e01b8152600481018390529192506001600160a01b031690631ffc735d906024016020604051808303816000875af1158015610741573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610765919061178c565b507f4be9ef9ae736055964ead1cf3c83a19c8b662b5df2bd4414776bb64d81f75d1584846040516107979291906117c1565b60405180910390a150505050565b60405163248f667760e01b815260009073e0398f7dfac494c530f6404afeac8669abed26799063248f6677906107df9085906004016117ea565b602060405180830381865af41580156107fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610820919061178c565b92915050565b60006000805160206119bd83398151915260028360405160200161084a919061181b565b60408051601f198184030181529082905261086491611851565b602060405180830381855afa158015610881573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906108a4919061178c565b6108209190611896565b60006108b86110fa565b838152602081018390526108cb81610958565b949350505050565b8281146108f35760405163ca3487f760e01b815260040160405180910390fd5b8260005b8181101561095057610948868683818110610914576109146118b8565b9050610140020180360381019061092b91906118ce565b85858481811061093d5761093d6118b8565b9050604002016105fb565b6001016108f7565b505050505050565b6040516314d2f97b60e11b81526000907307490eba00dc4aca6721d052fa4c5002aa077233906329a5f2f6906107df9085906004016118eb565b600061099c611118565b82515181528251602090810151818301528301518160026020020152604083015160608201526109cb816107a5565b9392505050565b60006109dc611136565b8351518152835160209081015190820152835160409081015190820152835160609081015190820152835160809081015190820152610a19611136565b845160a001518152845160c001516020820152845160e00151604080830191909152855161010001516060830152855161012001516080808401919091528151908101909152610a979080610a6d85610b9b565b8152602001610a7b84610b9b565b81526020018660000151815260200186602001518152506107a5565b95945050505050565b6000610acc7f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f00000000000000000000000000000000000000000000000000000000000000008111610b0e57604051630931513d60e11b815260040160405180910390fd5b600b5460405163c15da65b60e01b8152600481018490526001600160a01b039091169063c15da65b90602401600060405180830381600087803b158015610b5457600080fd5b505af1158015610b68573d6000803e3d6000fd5b50506040518492507f1245b881cb30fdad22b2f9fde2d5c2a3605bbdf272d5e8a2235d8c9e81aba2ce9150600090a25050565b604051630926f44b60e31b815260009073fd77833f10a29c76a6a0ede235eb651d744d0e2f90634937a258906107df908590600401611913565b6000610c017f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f00000000000000000000000000000000000000000000000000000000000000008111610c4357604051630931513d60e11b815260040160405180910390fd5b60045460ff1615610c675760405163b703d3c960e01b815260040160405180910390fd5b6004805460ff19166001178155600a546040805163423f3e1960e01b815290516000936001600160a01b039093169263423f3e19928082019260209290918290030181865afa158015610cbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce2919061178c565b60038190559050610cf1611154565b8181527f0000000000000000000000000000000000000000000000000000000000000000602082015260006040820152610d2a81610e10565b600555600a546040805163122db15360e01b815290516000926001600160a01b03169163122db1539160048083019260209291908290030181865afa158015610d77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9b919061178c565b6007819055905060015b818160ff166001901b64ffffffffff161015610dcd5780610dc58161193b565b915050610da5565b6008805460ff191660ff8316179055604051829085907f9f5164261ad26064467dc1be8861f75f2e57ae75579ebb4e500894b0ce9a982390600090a35050505050565b6040516304b98e1d60e31b815260009073bb0e724ce02e5e7edd31e632dc6e59f229a1126d906325cc70e8906107df90859060040161195a565b60005460ff1615610e6e576040516342a2e18d60e01b815260040160405180910390fd5b6000805460ff19166001908117909155600680549091019055610e8f6110fa565b7f12817f4161f2f5ded33f26c55735a77e80e4f8975483c8c2704745128417f71181526000602082018190528080610ec684610f6d565b600b54604051631ffc735d60e01b81526004810183905293965091945092506001600160a01b031690631ffc735d906024016020604051808303816000875af1158015610f17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3b919061178c565b507f4be9ef9ae736055964ead1cf3c83a19c8b662b5df2bd4414776bb64d81f75d158383604051610797929190611982565b610f75611172565b60408051808201909152600080825260208201526000610f9361118a565b84518152602080860151828201526040805180820182527f171e826ad4a870fd925e0bf0e87884e70e080879c2205ef10114f28a3b6f6dd781527f2bd407d897fbbca9f88adfd2d15252e69de8c1564eb4d3d27162e259172f1a1d818401528151928301909152828252909450925061100c84846109d2565b93959294505050565b6000806000805160206119bd833981519152848509905060006000805160206119bd833981519152848509905060006000805160206119bd833981519152826000805160206119bd83398151915285620292fc0908905060006000805160206119bd83398151915280846000805160206119bd83398151915287620292f8090960010890506110b382826000805160206119bd8339815191526110bf565b15979650505050505050565b6000838381116110d6576110d383826119a9565b90505b82806110e4576110e4611880565b60006110f08684611779565b0895945050505050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b604051806020016040528061118561118a565b905290565b604051806101400160405280600a906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156111e3576111e36111a9565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611212576112126111a9565b604052919050565b600061014080838503121561122e57600080fd5b604051602080820182811067ffffffffffffffff82111715611252576112526111a9565b806040525081935085601f86011261126957600080fd5b6112716111bf565b92850192808785111561128357600080fd5b865b8581101561129c5780358352918301918301611285565b509092525091949350505050565b6000808284036101808112156112bf57600080fd5b6112c9858561121a565b9250604061013f19820112156112de57600080fd5b50610140830190509250929050565b6000608082840312156112ff57600080fd5b82601f83011261130e57600080fd5b6040516080810181811067ffffffffffffffff82111715611331576113316111a9565b60405280608084018581111561134657600080fd5b845b81811015611360578035835260209283019201611348565b509195945050505050565b6000602080838503121561137e57600080fd5b823567ffffffffffffffff8082111561139657600080fd5b818501915085601f8301126113aa57600080fd5b8135818111156113bc576113bc6111a9565b8060051b91506113cd8483016111e9565b81815291830184019184810190888411156113e757600080fd5b938501935b83851015611405578435825293850193908501906113ec565b98975050505050505050565b6000806040838503121561142457600080fd5b50508035926020909101359150565b6000806000806040858703121561144957600080fd5b843567ffffffffffffffff8082111561146157600080fd5b818701915087601f83011261147557600080fd5b81358181111561148457600080fd5b8860206101408302850101111561149a57600080fd5b6020928301965094509086013590808211156114b557600080fd5b818701915087601f8301126114c957600080fd5b8135818111156114d857600080fd5b8860208260061b85010111156114ed57600080fd5b95989497505060200194505050565b60006040828403121561150e57600080fd5b82601f83011261151d57600080fd5b6040516040810181811067ffffffffffffffff82111715611540576115406111a9565b806040525080604084018581111561134657600080fd5b60006040828403121561156957600080fd5b6040516040810181811067ffffffffffffffff8211171561158c5761158c6111a9565b604052823581526020928301359281019290925250919050565b6000608082840312156115b857600080fd5b6040516060810181811067ffffffffffffffff821117156115db576115db6111a9565b6040526115e88484611557565b815260408301356020820152606083013560408201528091505092915050565b600080610180838503121561161c57600080fd5b611626848461121a565b9150611636846101408501611557565b90509250929050565b60006020828403121561165157600080fd5b5035919050565b600060a0828403121561166a57600080fd5b82601f83011261167957600080fd5b60405160a0810181811067ffffffffffffffff8211171561169c5761169c6111a9565b6040528060a084018581111561134657600080fd5b6000606082840312156116c357600080fd5b82601f8301126116d257600080fd5b6040516060810181811067ffffffffffffffff821117156116f5576116f56111a9565b60405280606084018581111561134657600080fd5b80518260005b600a81101561172f578251825260209283019290910190600101611710565b5050505050565b6101a08101611745828661170a565b83516101408301526020909301516101608201526101800152919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561082057610820611763565b60006020828403121561179e57600080fd5b5051919050565b6000604082840312156117b757600080fd5b6109cb8383611557565b61018081016117d0828561170a565b823561014083015260208301356101608301529392505050565b60808101818360005b60048110156118125781518352602092830192909101906001016117f3565b50505092915050565b815160009082906020808601845b8381101561184557815185529382019390820190600101611829565b50929695505050505050565b6000825160005b818110156118725760208186018101518583015201611858565b506000920191825250919050565b634e487b7160e01b600052601260045260246000fd5b6000826118b357634e487b7160e01b600052601260045260246000fd5b500690565b634e487b7160e01b600052603260045260246000fd5b600061014082840312156118e157600080fd5b6109cb838361121a565b60408101818360005b60028110156118125781518352602092830192909101906001016118f4565b60a08101818360005b600581101561181257815183526020928301929091019060010161191c565b600060ff821660ff810361195157611951611763565b60010192915050565b60608101818360005b6003811015611812578151835260209283019290910190600101611963565b6101808101611991828561170a565b825161014083015260208301516101608301526109cb565b808201808211156108205761082061176356fe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a2646970667358221220ee918fd206d19d51e7802d50e33e7d2078dbfa8fe1f17932de0f7d396db34da864736f6c6343000814003330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a26469706673582212204bd0ede232512a0e1e4288fc8656baf8d4eddb834b6a8ef8b1dddbdfa3c0e25a64736f6c63430008140033

Deployed Bytecode

0x60806040523480156200001157600080fd5b50600436106200003a5760003560e01c8063683f3dc3146200003f57806370f7b361146200005f575b600080fd5b62000048600a81565b60405160ff90911681526020015b60405180910390f35b620000766200007036600462000229565b6200008f565b6040516001600160a01b03909116815260200162000056565b600080620000a46040870160208801620002bf565b604051620000b2906200020d565b60ff9091168152602001604051809103906000f080158015620000d9573d6000803e3d6000fd5b50905060006040518060400160405280866001600160a01b03168152602001836001600160a01b03168152509050600088888884886040516200011c906200021b565b6200012c959493929190620002e4565b604051809103906000f08015801562000149573d6000803e3d6000fd5b5060405163f2fde38b60e01b81526001600160a01b0380831660048301529192509084169063f2fde38b90602401600060405180830381600087803b1580156200019257600080fd5b505af1158015620001a7573d6000803e3d6000fd5b50505050806001600160a01b031663e1c7392a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015620001e757600080fd5b505af1158015620001fc573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6122dc806200038183390190565b61212c806200265d83390190565b60008060008060008587036101208112156200024457600080fd5b863595506080601f19820112156200025b57600080fd5b6020870194506040609f19820112156200027457600080fd5b5060a08601925060e08601356001600160a01b03811681146200029657600080fd5b94979396509194610100013592915050565b803560ff81168114620002ba57600080fd5b919050565b600060208284031215620002d257600080fd5b620002dd82620002a8565b9392505050565b858152610140810160ff620002f987620002a8565b16602083015260ff6200030f60208801620002a8565b16604083015260ff6200032560408801620002a8565b16606083015260ff6200033b60608801620002a8565b166080830152843560a083015260209485013560c083015283516001600160a01b0390811660e08401529390940151909216610100830152610120909101529291505056fe60e06040523480156200001157600080fd5b50604051620022dc380380620022dc83398101604081905262000034916200063d565b8080600533806200006057604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6200006b81620005ed565b50816000036200008e5760405163682e504160e11b815260040160405180910390fd5b6020821115620000bc57604051637ccdcc9760e11b8152600481018390526020602482015260440162000057565b80600214158015620000cf575080600514155b15620000ee57604051636f7b6c0360e01b815260040160405180910390fd5b6000805460ff60a01b191660028314600160a01b02179055608082905260a08190526200011c82826200076c565b60c05250507f12817f4161f2f5ded33f26c55735a77e80e4f8975483c8c2704745128417f7116101725550507f1c8de1edeabc24fc4c1595acaabb70be9b70f351d58c6fa338e1e9a994413bfb610173557f22fcda488c14b34fc60eb073fbe92fe10793e2ab14682e0f057332ddbef3d55c610174557f2db474db7c7212646cb15c6177d87be30711e6c04f1139d8e495ef1d1d998227610175557efde404053ec39a19f6ac347121a2264815dda84f910a388cb372e967a5d08c610176557f0723792ffab6ec6cfb3ece1509b9b4fb07e5bdb2299d1538e6e1db916f90cf89610177557f2a4392ec4e3d1811cd6a950cc865ee6f2342910a6551c5dce38cb995576c7c70610178557f1dead4c14f75e9d8449c80b648dcd4694c2ee50da2ba16e5e438f0d77ab02e34610179557f124c53ce0953fffb7ab5e3c143df6cd48ba747d3959fcb8086405d763ed5455061017a557f02bae19605746a8cd3f0927b2c01630f36f4d1bab9216ca839833e7ff6efa20661017b557f1f8375099becf17173d457d0d07bfb74c7067df1143b5ad987046e8e66817bc961017c557f0e13e954d61bb3fa3b03e7d136ca909b610fa2ca4443d920d94d16684f2b83d461017d557f1416ef2fc4f88fcfc4f9eb12f8e214b1c3e31c6c10ece9cfa51f078a3bbf345761017e557f032f915ff71e198a7955d2697249f40fb94c65812ed24e670c9700f52fdf6e0e61017f557f08bfebf4b3ddb0f8c51dd40193f5996da9f3d799ee0d8beb6be4038132df60b4610180557f065ac498cf4a5acaeb3b6cee826da9f834c961fa39feff6ae925b90dff79b613610181557f2e72c628101a93201b912a3e3fe96d39b0a9076ec39b7935a015c59bb32b8a2a610182557f19bba68e7b9da1e6ec42e52d7ab2adaf3b6a5521b1a454ec70f62e0ab702c085610183557f0de1f72745a5af2a34cac412e00eb6c8b5db1f3b52fa1bff88076c2726b83b08610184557f2e8f152603b2fac10d6a14c841327c23c502537367ccb1e42fab9a3bd9db2a8d610185557f14e16c3e0dcfd7e621a32627ebf37f6c0afb4467d34c7b7aeffded11769dec85610186557f0be1e62127948b4805c85a1d836574f0892ca6473fcde98f3fd1781248a9768f610187557f0930288fbd7c849197c8372f1dd8f9087f8a03f09b9cd904a469c15ef6b1b515610188557f231cac34e215e3f404d2fcfb79e0705deeb3d40978f0ee31072f6cbc1b579e33610189557f2e0e3cd2718ac7199b81dc14e841de40a9536b7ffe95fa1fc9c6b799e43e2c9761018a557f0718452506f0a232e98966d84b1a4675a66bd80263a2dc58bdac873825752fc361018b557f162d4ed998307d6e132edbf5c11f62f53d4636aa10cb3c2244c2bf5577168c3761018c557f247d6a5544a8f295a894ae77c7efcdcbf52e3bf4e5d0c0d2f40557a61d44984861018d557f0b8de3868471f109e91670daca698dba917d1c5535821f33aa9598d1db8e3d1961018e557f29851997020f527c92e20f030d232b81d334144a641e6a8866b46dd925005bbb61018f557f1a9cfcbe29a2b6503a03049727c0bca3111afd62f2836f392080321d1b4ef642610190557f1aa3ead91fa89cc1d6cb1d0eb76a27190c6abfdd3265d6d0a1e5c58feddaddf6610191557f0702fc26a7d367e6677efefd95204a7e00144c2fc7dbc2a581aa00d99f51f0816101925562000781565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156200065057600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600181815b80851115620006ae57816000190482111562000692576200069262000657565b80851615620006a057918102915b93841c939080029062000672565b509250929050565b600082620006c75750600162000766565b81620006d65750600062000766565b8160018114620006ef5760028114620006fa576200071a565b600191505062000766565b60ff8411156200070e576200070e62000657565b50506001821b62000766565b5060208310610133831016604e8410600b84101617156200073f575081810a62000766565b6200074b83836200066d565b806000190482111562000762576200076262000657565b0290505b92915050565b60006200077a8383620006b6565b9392505050565b60805160a05160c051611aad6200082f600039600081816103ea01528181610a2501528181610ac201528181610c7f0152610d820152600081816103230152818161056e015281816106e401528181610bb401528181610ec301528181611037015261129801526000818161041a0152818161047b0152818161054401528181610bed01528181610cb801528181610d0201528181610e6401528181610f1a01526111d30152611aad6000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c806381d6a24a116100c3578063c00bdbcc1161007c578063c00bdbcc146102b8578063c15da65b146102cb578063d9c55ce1146102de578063dda89a6e146102e6578063e93fb4d4146102f0578063f2fde38b1461030357600080fd5b806381d6a24a146102455780638da5cb5b146102615780639cfced971461027c578063a27154ba1461028f578063b6a64acd14610297578063bea140b3146102a557600080fd5b806358bfc3791161011557806358bfc379146101cc5780635bb93995146101df5780635bf1fa4d146101f257806362a361bb1461020557806369e7c58614610218578063715018a61461023b57600080fd5b80631b9b8aa71461015d5780631ffc735d1461018357806324a47aeb146101965780633bfa6fce146101a95780633dfb88b2146101b15780633e1a8cc1146101c4575b600080fd5b61017061016b3660046114ba565b610316565b6040519081526020015b60405180910390f35b6101706101913660046114ba565b610399565b6101706101a43660046114ba565b6104c7565b6101706106d8565b6101706101bf36600461151a565b610723565b6101706107a4565b6101706101da366004611598565b6107d3565b6101706101ed36600461163e565b61086d565b61017061020036600461163e565b610892565b610170610213366004611660565b610931565b61016e5461022b90610100900460ff1681565b604051901515815260200161017a565b61024361096b565b005b610170546001546040805192835260208301919091520161017a565b6000546040516001600160a01b03909116815260200161017a565b61017061028a3660046116bb565b61097f565b610170602081565b61016e5461022b9060ff1681565b6101706102b3366004611714565b6109b9565b6102436102c63660046114ba565b6109f3565b6102436102d93660046114ba565b610a6f565b610243610c75565b6101706101715481565b6101706102fe3660046114ba565b610dbf565b61024361031136600461176d565b610dfa565b61017154600090610347837f0000000000000000000000000000000000000000000000000000000000000000611897565b101561037d5761017154604051627289df60e61b8152610374918491600401918252602082015260400190565b60405180910390fd5b61014d8260218110610391576103916118a3565b015492915050565b60006103a3610e35565b50610171546103b3826000610e62565b6103be8160016118b9565b610171556103cf61014d600061141f565b600061016f5561016e805460ff191690556101715461040f907f0000000000000000000000000000000000000000000000000000000000000000906118cc565b6000036104c25760027f000000000000000000000000000000000000000000000000000000000000000060218110610449576104496118a3565b600402015460018054600090815261014c6020526040812092909255805491610471836118ee565b90915550600290507f0000000000000000000000000000000000000000000000000000000000000000602181106104aa576104aa6118a3565b6004020160008091018190556104c29060869061141f565b919050565b60006104d1610e35565b816000036104f257604051630543d40760e11b815260040160405180910390fd5b61016e5460ff1661051657604051631e596e4360e11b815260040160405180910390fd5b602082111561054257604051632cd31ae960e01b81526004810183905260206024820152604401610374565b7f00000000000000000000000000000000000000000000000000000000000000005b61017154610592827f0000000000000000000000000000000000000000000000000000000000000000611897565b10156105aa57806105a2816118ee565b915050610564565b808310156105d457604051627289df60e61b81526004810184905260248101829052604401610374565b8083036106105761016f5461014d84602181106105f3576105f36118a3565b0155505061016e805461ff00191661010017905561016f54919050565b61016f549150805b838110156106aa57600061062b82610fa3565b600054909150600160a01b900460ff16156106635761064861142e565b8481526020810182905261065b81610931565b945050610697565b61066b61144c565b848152602081018290526040810182905260608101829052608081018290526106938161097f565b9450505b50806106a2816118ee565b915050610618565b508161014d84602181106106c0576106c06118a3565b015561016e805461ff00191661010017905550919050565b60015b600154610708827f0000000000000000000000000000000000000000000000000000000000000000611897565b10156107205780610718816118ee565b9150506106db565b90565b60405163248f667760e01b815260009073e0398f7dfac494c530f6404afeac8669abed26799063248f66779061075d908590600401611907565b602060405180830381865af415801561077a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079e9190611938565b92915050565b61016e5460009060ff166107cb57604051631e596e4360e11b815260040160405180910390fd5b5061016f5490565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016002836040516020016108099190611951565b60408051601f198184030181529082905261082391611987565b602060405180830381855afa158015610840573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906108639190611938565b61079e91906118cc565b600061087761142e565b8381526020810183905261088a81610931565b949350505050565b600061089c61144c565b600284602181106108af576108af6118a3565b60040201548152600284602181106108c9576108c96118a3565b60040201600101548160016020020152600284602181106108ec576108ec6118a3565b600402016002015481600260200201526002846021811061090f5761090f6118a3565b6004020160030154816003602002015282816004602002015261088a8161097f565b6040516314d2f97b60e11b81526000907307490eba00dc4aca6721d052fa4c5002aa077233906329a5f2f69061075d9085906004016119b6565b610973610e35565b61097d6000610fb9565b565b604051630926f44b60e31b815260009073fd77833f10a29c76a6a0ede235eb651d744d0e2f90634937a2589061075d9085906004016119de565b6040516304b98e1d60e31b815260009073bb0e724ce02e5e7edd31e632dc6e59f229a1126d906325cc70e89061075d908590600401611a06565b6109fb610e35565b60018054600090815261014c6020526040812083905581549190610a1e836118ee565b91905055507f00000000000000000000000000000000000000000000000000000000000000006101716000828254610a5691906118b9565b9091555050600061016f555061016e805460ff19169055565b610a77610e35565b61016e5460ff1615610a9c57604051630d36aec160e01b815260040160405180910390fd5b61017154600003610ac0576040516316a0341160e11b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000061017154610aef91906118cc565b15610afc57610afc610c75565b600154600103610b2557610b106000610dbf565b61016f5561016e805460ff1916600117905550565b6000610b2f6106d8565b610170549091506000905b600154811015610bab578315801590610b5257508382145b15610b5d5750505050565b610b74610b6c61017054610dbf565b600085611009565b6101708054906000610b85836118ee565b91905055508180610b95906118ee565b9250508080610ba3906118ee565b915050610b3a565b506000610bd8837f0000000000000000000000000000000000000000000000000000000000000000611897565b90506001546101705403610c41576000610c117f0000000000000000000000000000000000000000000000000000000000000000610fa3565b6001549091505b82811015610c3e57610c2c82600087611009565b80610c36816118ee565b915050610c18565b50505b60a78360218110610c5457610c546118a3565b600402016000015461016f55505061016e805460ff19166001179055505b50565b610c7d610e35565b7f000000000000000000000000000000000000000000000000000000000000000061017154610cac91906118cc565b600003610cf457610cdc7f0000000000000000000000000000000000000000000000000000000000000000610fa3565b600154600090815261014c6020526040902055610d65565b610cfe60006111d1565b60027f000000000000000000000000000000000000000000000000000000000000000060218110610d3157610d316118a3565b6004020154600154600090815261014c6020526040812091909155610d589060029061146a565b610d6561014d600061141f565b60006001546001610d7691906118b9565b60018190559050610da77f000000000000000000000000000000000000000000000000000000000000000082611a2e565b6101715550600061016f5561016e805460ff19169055565b60008160015411610de65760405163042a2e7160e11b815260048101839052602401610374565b50600090815261014c602052604090205490565b610e02610e35565b6001600160a01b038116610e2c57604051631e4fbdf760e01b815260006004820152602401610374565b610c7281610fb9565b6000546001600160a01b0316331461097d5760405163118cdaa760e01b8152336004820152602401610374565b7f0000000000000000000000000000000000000000000000000000000000000000811115610ea35760405163d1459f7960e01b815260040160405180910390fd5b600060868260218110610eb857610eb86118a3565b01549050610ee760017f0000000000000000000000000000000000000000000000000000000000000000611a45565b8114610f6c578260028360218110610f0157610f016118a3565b600402018260048110610f1657610f166118a3565b01557f00000000000000000000000000000000000000000000000000000000000000008214610f675760868260218110610f5257610f526118a3565b018054906000610f61836118ee565b91905055505b505050565b610f76828461133d565b925060868260218110610f8b57610f8b6118a3565b600091015581610f9a816118ee565b92505050610ea3565b60006101728260218110610391576103916118a3565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8082111561101657505050565b600061012b836021811061102c5761102c6118a3565b0154905061105b60017f0000000000000000000000000000000000000000000000000000000000000000611a45565b81146110b9578360a78460218110611075576110756118a3565b60040201826004811061108a5761108a6118a3565b015561012b83602181106110a0576110a06118a3565b0180549060006110af836118ee565b91905055506111cb565b60008054600160a01b900460ff1615611106576110d461142e565b60a785602181106110e7576110e76118a3565b60040201548152602081018690526110fe81610931565b91505061119b565b61110e61144c565b60005b838160ff1610156111755760a7866021811061112f5761112f6118a3565b600402018160ff1660048110611147576111476118a3565b0154828260ff166005811061115e5761115e6118a3565b60200201528061116d81611a58565b915050611111565b5085818460058110611189576111896118a3565b60200201526111978161097f565b9150505b61012b84602181106111af576111af6118a3565b60009101556111c9816111c38660016118b9565b85611009565b505b50505050565b7f0000000000000000000000000000000000000000000000000000000000000000811015610c725760006086826021811061120e5761120e6118a3565b01549050801561131257600061122261144c565b600061122d85610fa3565b905060005b848160ff1610156112965760028660218110611250576112506118a3565b600402018160ff1660048110611268576112686118a3565b0154838260ff166005811061127f5761127f6118a3565b60200201528061128e81611a58565b915050611232565b7f00000000000000000000000000000000000000000000000000000000000000008160ff1610156112ee5781838260ff16600581106112d7576112d76118a3565b6020020152806112e681611a58565b915050611296565b6112f78361097f565b935061130d846113088860016118b9565b610e62565b505050505b60868260218110611325576113256118a3565b600091015581611334816118ee565b925050506111d1565b600061134761144c565b6002846021811061135a5761135a6118a3565b6004020154815260028460218110611374576113746118a3565b6004020160010154816001602002015260028460218110611397576113976118a3565b60040201600201548160026020020152600284602181106113ba576113ba6118a3565b600402016003015481600360200201528281600460200201526113dc8161097f565b9150600284602181106113f1576113f16118a3565b60040201600061141891905060008155600101600081556001016000815560010160009055565b5092915050565b50610c72906021810190611479565b60405180604001604052806002906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b50610c72906084810190611492565b5b8082111561148e576000815560010161147a565b5090565b8082111561148e57600080825560018201819055600282018190556003820155600401611492565b6000602082840312156114cc57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611512576115126114d3565b604052919050565b60006080828403121561152c57600080fd5b82601f83011261153b57600080fd5b6040516080810181811067ffffffffffffffff8211171561155e5761155e6114d3565b60405280608084018581111561157357600080fd5b845b8181101561158d578035835260209283019201611575565b509195945050505050565b600060208083850312156115ab57600080fd5b823567ffffffffffffffff808211156115c357600080fd5b818501915085601f8301126115d757600080fd5b8135818111156115e9576115e96114d3565b8060051b91506115fa8483016114e9565b818152918301840191848101908884111561161457600080fd5b938501935b8385101561163257843582529385019390850190611619565b98975050505050505050565b6000806040838503121561165157600080fd5b50508035926020909101359150565b60006040828403121561167257600080fd5b82601f83011261168157600080fd5b6040516040810181811067ffffffffffffffff821117156116a4576116a46114d3565b806040525080604084018581111561157357600080fd5b600060a082840312156116cd57600080fd5b82601f8301126116dc57600080fd5b60405160a0810181811067ffffffffffffffff821117156116ff576116ff6114d3565b6040528060a084018581111561157357600080fd5b60006060828403121561172657600080fd5b82601f83011261173557600080fd5b6040516060810181811067ffffffffffffffff82111715611758576117586114d3565b60405280606084018581111561157357600080fd5b60006020828403121561177f57600080fd5b81356001600160a01b038116811461179657600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156117ee5781600019048211156117d4576117d461179d565b808516156117e157918102915b93841c93908002906117b8565b509250929050565b6000826118055750600161079e565b816118125750600061079e565b816001811461182857600281146118325761184e565b600191505061079e565b60ff8411156118435761184361179d565b50506001821b61079e565b5060208310610133831016604e8410600b8410161715611871575081810a61079e565b61187b83836117b3565b806000190482111561188f5761188f61179d565b029392505050565b600061179683836117f6565b634e487b7160e01b600052603260045260246000fd5b8082018082111561079e5761079e61179d565b6000826118e957634e487b7160e01b600052601260045260246000fd5b500690565b6000600182016119005761190061179d565b5060010190565b60808101818360005b600481101561192f578151835260209283019290910190600101611910565b50505092915050565b60006020828403121561194a57600080fd5b5051919050565b815160009082906020808601845b8381101561197b5781518552938201939082019060010161195f565b50929695505050505050565b6000825160005b818110156119a8576020818601810151858301520161198e565b506000920191825250919050565b60408101818360005b600281101561192f5781518352602092830192909101906001016119bf565b60a08101818360005b600581101561192f5781518352602092830192909101906001016119e7565b60608101818360005b600381101561192f578151835260209283019290910190600101611a0f565b808202811582820484141761079e5761079e61179d565b8181038181111561079e5761079e61179d565b600060ff821660ff8103611a6e57611a6e61179d565b6001019291505056fea2646970667358221220de48377ebab560ef190138d15ea2cd48ec74d706562bdc76aca8c6093ed43a8e64736f6c634300081400336101206040526040516200212c3803806200212c8339810160408190526200002791620003da565b825160208401516200003a91906200013a565b62000058576040516379fae7af60e01b815260040160405180910390fd5b8251600181905560208401516002819055620000759190620001ef565b6080528151600a80546001600160a01b039283166001600160a01b031991821617909155602080850151600b80549190941692169190911790915560c08690528451600980549287015160408801805160608a015160ff90811663010000000263ff0000001992821662010000029290921663ffff0000199482166101000261ffff199098169190961617959095179190911692909217929092179091554260a05260e0829052516200012a906005620005c8565b61010052506200066f9350505050565b6000806000805160206200210c833981519152848509905060006000805160206200210c833981519152848509905060006000805160206200210c833981519152826000805160206200210c83398151915285620292fc0908905060006000805160206200210c83398151915280846000805160206200210c83398151915287620292f809096001089050620001e182826000805160206200210c83398151915262000218565b159450505050505b92915050565b6000620001fb620002db565b8381526020810183905262000210816200025b565b949350505050565b60008383811162000232576200022f8382620005f6565b90505b8280620002435762000243620005e0565b60006200025186846200060c565b0895945050505050565b6040516314d2f97b60e11b81526000907307490eba00dc4aca6721d052fa4c5002aa077233906329a5f2f6906200029790859060040162000622565b602060405180830381865af4158015620002b5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001e9919062000655565b60405180604001604052806002906020820280368337509192915050565b604080519081016001600160401b03811182821017156200032a57634e487b7160e01b600052604160045260246000fd5b60405290565b604051608081016001600160401b03811182821017156200032a57634e487b7160e01b600052604160045260246000fd5b805160ff811681146200037357600080fd5b919050565b6001600160a01b03811681146200038e57600080fd5b50565b600060408284031215620003a457600080fd5b620003ae620002f9565b90508151620003bd8162000378565b81526020820151620003cf8162000378565b602082015292915050565b6000806000806000858703610140811215620003f557600080fd5b865195506080601f19820112156200040c57600080fd5b6200041662000330565b620004246020890162000361565b8152620004346040890162000361565b6020820152620004476060890162000361565b60408201526200045a6080890162000361565b606082015294506040609f19820112156200047457600080fd5b506200047f620002f9565b60a0870151815260c087015160208201529250620004a18760e0880162000391565b915061012086015190509295509295909350565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156200050c578160001904821115620004f057620004f0620004b5565b80851615620004fe57918102915b93841c9390800290620004d0565b509250929050565b6000826200052557506001620001e9565b816200053457506000620001e9565b81600181146200054d5760028114620005585762000578565b6001915050620001e9565b60ff8411156200056c576200056c620004b5565b50506001821b620001e9565b5060208310610133831016604e8410600b84101617156200059d575081810a620001e9565b620005a98383620004cb565b8060001904821115620005c057620005c0620004b5565b029392505050565b6000620005d960ff84168362000514565b9392505050565b634e487b7160e01b600052601260045260246000fd5b80820180821115620001e957620001e9620004b5565b81810381811115620001e957620001e9620004b5565b60408101818360005b60028110156200064c5781518352602092830192909101906001016200062b565b50505092915050565b6000602082840312156200066857600080fd5b5051919050565b60805160a05160c05160e05161010051611a12620006fa60003960008181610299015261066b01526000818161033a0152610cf6015260008181610270015281816105100152818161062b01528181610ad00152610c0501526000818161024f015281816104e70152818161060201528181610aa70152610bdc015260006103940152611a126000f3fe608060405234801561001057600080fd5b50600436106101d95760003560e01c80637028bb0e11610104578063ac98e5df116100a2578063e1c7392a11610071578063e1c7392a14610490578063e33b13a014610498578063edbfe83f146104b5578063fba630f2146104d757600080fd5b8063ac98e5df146103e4578063bc14ee2b1461043a578063bea140b314610474578063c17268d91461048757600080fd5b80638aa0ba92116100de5780638aa0ba921461038f5780639c971729146103b65780639cfced97146103c9578063a28bc38c146103dc57600080fd5b80637028bb0e1461035c5780637d0a81c8146103695780638a2a3dfb1461037c57600080fd5b80634f367f0f1161017c578063623f54ac1161014b578063623f54ac146102f557806362a361bb14610308578063683f3dc31461031b5780636d582d341461033557600080fd5b80634f367f0f146102bb57806358bfc379146102c65780635bb93995146102d95780635d5909dd146102ec57600080fd5b806331e766a5116101b857806331e766a5146102175780633dfb88b21461023a5780634909229f1461024d5780634966efd61461029457600080fd5b8062329f2f146101de5780630f4cf692146101e857806327bea0da14610204575b600080fd5b6101e66104e0565b005b6101f160065481565b6040519081526020015b60405180910390f35b6101e66102123660046112aa565b6105fb565b600154600254610225919082565b604080519283526020830191909152016101fb565b6101f16102483660046112ed565b6107a5565b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000610225565b6101f17f000000000000000000000000000000000000000000000000000000000000000081565b600754600654610225565b6101f16102d436600461136b565b610826565b6101f16102e7366004611411565b6108ae565b6101f160075481565b6101e6610303366004611433565b6108d3565b6101f16103163660046114fc565b610958565b610323600a81565b60405160ff90911681526020016101fb565b6101f17f000000000000000000000000000000000000000000000000000000000000000081565b6008546103239060ff1681565b6101f16103773660046115a6565b610992565b6101f161038a366004611608565b6109d2565b6101f17f000000000000000000000000000000000000000000000000000000000000000081565b6101e66103c436600461163f565b610aa0565b6101f16103d7366004611658565b610b9b565b6101e6610bd5565b60095461040d9060ff808216916101008104821691620100008204811691630100000090041684565b6040805160ff958616815293851660208501529184169183019190915290911660608201526080016101fb565b600a54600b54610454916001600160a01b03908116911682565b604080516001600160a01b039384168152929091166020830152016101fb565b6101f16104823660046116b1565b610e10565b6101f160055481565b6101e6610e4a565b6004546104a59060ff1681565b60405190151581526020016101fb565b6104c86104c33660046114fc565b610f6d565b6040516101fb93929190611736565b6101f160035481565b600061050c7f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f0000000000000000000000000000000000000000000000000000000000000000811161054e57604051630931513d60e11b815260040160405180910390fd5b600b546009546040516324a47aeb60e01b81526201000090910460ff1660048201526000916001600160a01b0316906324a47aeb906024016020604051808303816000875af11580156105a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c9919061178c565b60405190915081907fc5624680ab5d50c84507f9e0dc2032163de2bda906ab8a661a53dd4d43bd5dc790600090a25050565b60006106277f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f000000000000000000000000000000000000000000000000000000000000000081106106695760405163148fb9a960e31b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000600654106106ab57604051631ec0b2f760e01b815260040160405180910390fd5b6106ba82356020840135611015565b6106d7576040516379fae7af60e01b815260040160405180910390fd5b60068054600101905560006106f58461038a368690038601866117a5565b600b54604051631ffc735d60e01b8152600481018390529192506001600160a01b031690631ffc735d906024016020604051808303816000875af1158015610741573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610765919061178c565b507f4be9ef9ae736055964ead1cf3c83a19c8b662b5df2bd4414776bb64d81f75d1584846040516107979291906117c1565b60405180910390a150505050565b60405163248f667760e01b815260009073e0398f7dfac494c530f6404afeac8669abed26799063248f6677906107df9085906004016117ea565b602060405180830381865af41580156107fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610820919061178c565b92915050565b60006000805160206119bd83398151915260028360405160200161084a919061181b565b60408051601f198184030181529082905261086491611851565b602060405180830381855afa158015610881573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906108a4919061178c565b6108209190611896565b60006108b86110fa565b838152602081018390526108cb81610958565b949350505050565b8281146108f35760405163ca3487f760e01b815260040160405180910390fd5b8260005b8181101561095057610948868683818110610914576109146118b8565b9050610140020180360381019061092b91906118ce565b85858481811061093d5761093d6118b8565b9050604002016105fb565b6001016108f7565b505050505050565b6040516314d2f97b60e11b81526000907307490eba00dc4aca6721d052fa4c5002aa077233906329a5f2f6906107df9085906004016118eb565b600061099c611118565b82515181528251602090810151818301528301518160026020020152604083015160608201526109cb816107a5565b9392505050565b60006109dc611136565b8351518152835160209081015190820152835160409081015190820152835160609081015190820152835160809081015190820152610a19611136565b845160a001518152845160c001516020820152845160e00151604080830191909152855161010001516060830152855161012001516080808401919091528151908101909152610a979080610a6d85610b9b565b8152602001610a7b84610b9b565b81526020018660000151815260200186602001518152506107a5565b95945050505050565b6000610acc7f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f00000000000000000000000000000000000000000000000000000000000000008111610b0e57604051630931513d60e11b815260040160405180910390fd5b600b5460405163c15da65b60e01b8152600481018490526001600160a01b039091169063c15da65b90602401600060405180830381600087803b158015610b5457600080fd5b505af1158015610b68573d6000803e3d6000fd5b50506040518492507f1245b881cb30fdad22b2f9fde2d5c2a3605bbdf272d5e8a2235d8c9e81aba2ce9150600090a25050565b604051630926f44b60e31b815260009073fd77833f10a29c76a6a0ede235eb651d744d0e2f90634937a258906107df908590600401611913565b6000610c017f000000000000000000000000000000000000000000000000000000000000000042611779565b90507f00000000000000000000000000000000000000000000000000000000000000008111610c4357604051630931513d60e11b815260040160405180910390fd5b60045460ff1615610c675760405163b703d3c960e01b815260040160405180910390fd5b6004805460ff19166001178155600a546040805163423f3e1960e01b815290516000936001600160a01b039093169263423f3e19928082019260209290918290030181865afa158015610cbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce2919061178c565b60038190559050610cf1611154565b8181527f0000000000000000000000000000000000000000000000000000000000000000602082015260006040820152610d2a81610e10565b600555600a546040805163122db15360e01b815290516000926001600160a01b03169163122db1539160048083019260209291908290030181865afa158015610d77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9b919061178c565b6007819055905060015b818160ff166001901b64ffffffffff161015610dcd5780610dc58161193b565b915050610da5565b6008805460ff191660ff8316179055604051829085907f9f5164261ad26064467dc1be8861f75f2e57ae75579ebb4e500894b0ce9a982390600090a35050505050565b6040516304b98e1d60e31b815260009073bb0e724ce02e5e7edd31e632dc6e59f229a1126d906325cc70e8906107df90859060040161195a565b60005460ff1615610e6e576040516342a2e18d60e01b815260040160405180910390fd5b6000805460ff19166001908117909155600680549091019055610e8f6110fa565b7f12817f4161f2f5ded33f26c55735a77e80e4f8975483c8c2704745128417f71181526000602082018190528080610ec684610f6d565b600b54604051631ffc735d60e01b81526004810183905293965091945092506001600160a01b031690631ffc735d906024016020604051808303816000875af1158015610f17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3b919061178c565b507f4be9ef9ae736055964ead1cf3c83a19c8b662b5df2bd4414776bb64d81f75d158383604051610797929190611982565b610f75611172565b60408051808201909152600080825260208201526000610f9361118a565b84518152602080860151828201526040805180820182527f171e826ad4a870fd925e0bf0e87884e70e080879c2205ef10114f28a3b6f6dd781527f2bd407d897fbbca9f88adfd2d15252e69de8c1564eb4d3d27162e259172f1a1d818401528151928301909152828252909450925061100c84846109d2565b93959294505050565b6000806000805160206119bd833981519152848509905060006000805160206119bd833981519152848509905060006000805160206119bd833981519152826000805160206119bd83398151915285620292fc0908905060006000805160206119bd83398151915280846000805160206119bd83398151915287620292f8090960010890506110b382826000805160206119bd8339815191526110bf565b15979650505050505050565b6000838381116110d6576110d383826119a9565b90505b82806110e4576110e4611880565b60006110f08684611779565b0895945050505050565b60405180604001604052806002906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b604051806020016040528061118561118a565b905290565b604051806101400160405280600a906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156111e3576111e36111a9565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611212576112126111a9565b604052919050565b600061014080838503121561122e57600080fd5b604051602080820182811067ffffffffffffffff82111715611252576112526111a9565b806040525081935085601f86011261126957600080fd5b6112716111bf565b92850192808785111561128357600080fd5b865b8581101561129c5780358352918301918301611285565b509092525091949350505050565b6000808284036101808112156112bf57600080fd5b6112c9858561121a565b9250604061013f19820112156112de57600080fd5b50610140830190509250929050565b6000608082840312156112ff57600080fd5b82601f83011261130e57600080fd5b6040516080810181811067ffffffffffffffff82111715611331576113316111a9565b60405280608084018581111561134657600080fd5b845b81811015611360578035835260209283019201611348565b509195945050505050565b6000602080838503121561137e57600080fd5b823567ffffffffffffffff8082111561139657600080fd5b818501915085601f8301126113aa57600080fd5b8135818111156113bc576113bc6111a9565b8060051b91506113cd8483016111e9565b81815291830184019184810190888411156113e757600080fd5b938501935b83851015611405578435825293850193908501906113ec565b98975050505050505050565b6000806040838503121561142457600080fd5b50508035926020909101359150565b6000806000806040858703121561144957600080fd5b843567ffffffffffffffff8082111561146157600080fd5b818701915087601f83011261147557600080fd5b81358181111561148457600080fd5b8860206101408302850101111561149a57600080fd5b6020928301965094509086013590808211156114b557600080fd5b818701915087601f8301126114c957600080fd5b8135818111156114d857600080fd5b8860208260061b85010111156114ed57600080fd5b95989497505060200194505050565b60006040828403121561150e57600080fd5b82601f83011261151d57600080fd5b6040516040810181811067ffffffffffffffff82111715611540576115406111a9565b806040525080604084018581111561134657600080fd5b60006040828403121561156957600080fd5b6040516040810181811067ffffffffffffffff8211171561158c5761158c6111a9565b604052823581526020928301359281019290925250919050565b6000608082840312156115b857600080fd5b6040516060810181811067ffffffffffffffff821117156115db576115db6111a9565b6040526115e88484611557565b815260408301356020820152606083013560408201528091505092915050565b600080610180838503121561161c57600080fd5b611626848461121a565b9150611636846101408501611557565b90509250929050565b60006020828403121561165157600080fd5b5035919050565b600060a0828403121561166a57600080fd5b82601f83011261167957600080fd5b60405160a0810181811067ffffffffffffffff8211171561169c5761169c6111a9565b6040528060a084018581111561134657600080fd5b6000606082840312156116c357600080fd5b82601f8301126116d257600080fd5b6040516060810181811067ffffffffffffffff821117156116f5576116f56111a9565b60405280606084018581111561134657600080fd5b80518260005b600a81101561172f578251825260209283019290910190600101611710565b5050505050565b6101a08101611745828661170a565b83516101408301526020909301516101608201526101800152919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561082057610820611763565b60006020828403121561179e57600080fd5b5051919050565b6000604082840312156117b757600080fd5b6109cb8383611557565b61018081016117d0828561170a565b823561014083015260208301356101608301529392505050565b60808101818360005b60048110156118125781518352602092830192909101906001016117f3565b50505092915050565b815160009082906020808601845b8381101561184557815185529382019390820190600101611829565b50929695505050505050565b6000825160005b818110156118725760208186018101518583015201611858565b506000920191825250919050565b634e487b7160e01b600052601260045260246000fd5b6000826118b357634e487b7160e01b600052601260045260246000fd5b500690565b634e487b7160e01b600052603260045260246000fd5b600061014082840312156118e157600080fd5b6109cb838361121a565b60408101818360005b60028110156118125781518352602092830192909101906001016118f4565b60a08101818360005b600581101561181257815183526020928301929091019060010161191c565b600060ff821660ff810361195157611951611763565b60010192915050565b60608101818360005b6003811015611812578151835260209283019290910190600101611963565b6101808101611991828561170a565b825161014083015260208301516101608301526109cb565b808201808211156108205761082061176356fe30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a2646970667358221220ee918fd206d19d51e7802d50e33e7d2078dbfa8fe1f17932de0f7d396db34da864736f6c6343000814003330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a26469706673582212204bd0ede232512a0e1e4288fc8656baf8d4eddb834b6a8ef8b1dddbdfa3c0e25a64736f6c63430008140033

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.