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