Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- Voting
- Optimization enabled
- true
- Compiler version
- v0.4.26+commit.4563c3fc
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2025-04-01T07:09:11.885542Z
Contract source code
// File: contracts/abstracts/VotingBase.sol pragma solidity ^0.4.24; /** * @title Interface to be implemented by voting contract * @author LiorRabin * @dev abstract contract */ contract VotingBase { /** * @dev Possible states of quorum * @param InProgress - state while a ballot has not been finalized yet * @param Accepted - state after finalizing the ballot and majority have voted ActionChoices.Accept * @param Rejected - state after finalizing the ballot and majority have voted ActionChoices.Reject */ enum QuorumStates { Invalid, InProgress, Accepted, Rejected } /** * @dev Possible choices for a ballot */ enum ActionChoices { Invalid, Accept, Reject } /** * @dev This event will be emitted every time a new ballot is created * @param id ballot id * @param creator address of ballot creator */ event BallotCreated(uint256 indexed id, address indexed creator); /** * @dev This event will be emitted when a ballot if finalized * @param id ballot id */ event BallotFinalized(uint256 indexed id); /** * @dev This event will be emitted on each vote * @param id ballot id * @param decision voter decision (see VotingBase.ActionChoices) * @param voter address of the voter */ event Vote(uint256 indexed id, uint256 decision, address indexed voter); /** * @dev Function to be called when voting on a ballot * @param _id ballot id * @param _choice voter decision on the ballot (see VotingBase.ActionChoices) */ function vote(uint256 _id, uint256 _choice) external; } // File: contracts/eternal-storage/EternalStorage.sol pragma solidity ^0.4.24; /** * @title EternalStorage * @author LiorRabin * @dev This contract holds all the necessary state variables to carry out the storage of any contract and to support the upgrade functionality. */ contract EternalStorage { // Version number of the current implementation uint256 internal version; // Address of the current implementation address internal implementation; // Storage mappings mapping(bytes32 => uint256) internal uintStorage; mapping(bytes32 => string) internal stringStorage; mapping(bytes32 => address) internal addressStorage; mapping(bytes32 => bytes) internal bytesStorage; mapping(bytes32 => bool) internal boolStorage; mapping(bytes32 => int256) internal intStorage; mapping(bytes32 => uint256[]) internal uintArrayStorage; mapping(bytes32 => string[]) internal stringArrayStorage; mapping(bytes32 => address[]) internal addressArrayStorage; mapping(bytes32 => bytes[]) internal bytesArrayStorage; mapping(bytes32 => bool[]) internal boolArrayStorage; mapping(bytes32 => int256[]) internal intArrayStorage; mapping(bytes32 => bytes32[]) internal bytes32ArrayStorage; function isInitialized() public view returns(bool) { return boolStorage[keccak256(abi.encodePacked("isInitialized"))]; } function setInitialized(bool _status) internal { boolStorage[keccak256(abi.encodePacked("isInitialized"))] = _status; } } // File: contracts/interfaces/IConsensus.sol pragma solidity ^0.4.24; interface IConsensus { function currentValidatorsLength() external view returns(uint256); function currentValidatorsAtPosition(uint256 _p) external view returns(address); function getCycleDurationBlocks() external view returns(uint256); function getCurrentCycleEndBlock() external view returns(uint256); function cycle(address _validator) external; function isValidator(address _address) external view returns(bool); function getDelegatorsForRewardDistribution(address _validator, uint256 _rewardAmount) external view returns(address[], uint256[]); function isFinalized() external view returns(bool); function stakeAmount(address _address) external view returns(uint256); function totalStakeAmount() external view returns(uint256); } // File: contracts/eternal-storage/EternalStorageProxy.sol pragma solidity ^0.4.24; /** * @title EternalStorageProxy * @author LiorRabin * @dev This proxy holds the storage of the token contract and delegates every call to the current implementation set. * Besides, it allows to upgrade the token's behaviour towards further implementations, and provides authorization control functionalities */ contract EternalStorageProxy is EternalStorage { /** * @dev This event will be emitted every time the implementation gets upgraded * @param version representing the version number of the upgraded implementation * @param implementation representing the address of the upgraded implementation */ event Upgraded(uint256 version, address indexed implementation); /** * @dev This event will be emitted when ownership is renounces * @param previousOwner address which is renounced from ownership */ event OwnershipRenounced(address indexed previousOwner); /** * @dev This event will be emitted when ownership is transferred * @param previousOwner address which represents the previous owner * @param newOwner address which represents the new owner */ event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev This modifier verifies that msg.sender is the ProxyStorage contract */ modifier onlyProxyStorage() { require(msg.sender == getProxyStorage()); _; } /** * @dev This modifier verifies that msg.sender is the owner of the contract */ modifier onlyOwner() { require(msg.sender == getOwner()); _; } /** * @dev Constructor * @param _proxyStorage address representing the ProxyStorage contract * @param _implementation address representing the implementation contract */ constructor(address _proxyStorage, address _implementation) public { require(_implementation != address(0)); if (_proxyStorage != address(0)) { _setProxyStorage(_proxyStorage); } else { _setProxyStorage(address(this)); } _setImplementation(_implementation); _setOwner(msg.sender); } /** * @dev Fallback function allowing to perform a delegatecall to the given implementation. * This function will return whatever the implementation call returns */ // solhint-disable no-complex-fallback, no-inline-assembly function() payable public { address _impl = getImplementation(); require(_impl != address(0)); assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0 calldatacopy(0, 0, calldatasize) // Call the implementation. // out and outsize are 0 because we don't know the size yet let result := delegatecall(gas, _impl, 0, calldatasize, 0, 0) // Copy the returned data returndatacopy(0, 0, returndatasize) switch result // delegatecall returns 0 on error case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } // solhint-enable no-complex-fallback, no-inline-assembly /** * @dev Allows ProxyStorage contract (only) to upgrade the current implementation. * @param _newImplementation representing the address of the new implementation to be set. */ function upgradeTo(address _newImplementation) public onlyProxyStorage returns(bool) { if (_newImplementation == address(0)) return false; if (getImplementation() == _newImplementation) return false; uint256 _newVersion = getVersion() + 1; _setVersion(_newVersion); _setImplementation(_newImplementation); emit Upgraded(_newVersion, _newImplementation); return true; } /** * @dev Allows the current owner to relinquish ownership. */ function renounceOwnership() public onlyOwner { emit OwnershipRenounced(getOwner()); _setOwner(address(0)); } /** * @dev Allows the current owner to transfer control of the contract to a _newOwner. * @param _newOwner The address to transfer ownership to. */ function transferOwnership(address _newOwner) public onlyOwner { require(_newOwner != address(0)); emit OwnershipTransferred(getOwner(), _newOwner); _setOwner(_newOwner); } function getOwner() public view returns(address) { return addressStorage[keccak256(abi.encodePacked("owner"))]; } function _setOwner(address _owner) private { addressStorage[keccak256(abi.encodePacked("owner"))] = _owner; } function getVersion() public view returns(uint256) { return version; } function _setVersion(uint256 _newVersion) private { version = _newVersion; } function getImplementation() public view returns(address) { return implementation; } function _setImplementation(address _newImplementation) private { implementation = _newImplementation; } function getProxyStorage() public view returns(address) { return addressStorage[keccak256(abi.encodePacked("proxyStorage"))]; } function _setProxyStorage(address _proxyStorage) private { addressStorage[keccak256(abi.encodePacked("proxyStorage"))] = _proxyStorage; } } // File: openzeppelin-solidity/contracts/math/SafeMath.sol pragma solidity ^0.4.24; /** * @title SafeMath * @dev Math operations with safety checks that revert on error */ library SafeMath { int256 constant private INT256_MIN = -2**255; /** * @dev Multiplies two unsigned integers, reverts on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } /** * @dev Multiplies two signed integers, reverts on overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } require(!(a == -1 && b == INT256_MIN)); // This is the only case of overflow not detected by the check below int256 c = a * b; require(c / a == b); return c; } /** * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Integer division of two signed integers truncating the quotient, reverts on division by zero. */ function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0); // Solidity only automatically asserts when dividing by 0 require(!(b == -1 && a == INT256_MIN)); // This is the only case of overflow int256 c = a / b; return c; } /** * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); uint256 c = a - b; return c; } /** * @dev Subtracts two signed integers, reverts on overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a)); return c; } /** * @dev Adds two unsigned integers, reverts on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a); return c; } /** * @dev Adds two signed integers, reverts on overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a)); return c; } /** * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0); return a % b; } } // File: contracts/ProxyStorage.sol pragma solidity ^0.4.24; /** * @title Contract used for access and upgradeability to all network contracts * @author LiorRabin */ contract ProxyStorage is EternalStorage { using SafeMath for uint256; /** * @dev Available contract types on the network */ enum ContractTypes { Invalid, Consensus, BlockReward, ProxyStorage, Voting } /** * @dev This event will be emitted when all contract addresses have been initialized by the contract owner */ event ProxyInitialized( address consensus, address blockReward, address voting ); /** * @dev This event will be emitted each time a contract address is updated * @param contractType contract type (See ContractTypes enum) * @param contractAddress contract address set for the contract type */ event AddressSet(uint256 contractType, address contractAddress); /** * @dev This modifier verifies that msg.sender is the owner of the contract */ modifier onlyOwner() { require(msg.sender == addressStorage[OWNER]); _; } /** * @dev This modifier verifies that msg.sender is the voting contract which implement proxy address change */ modifier onlyVoting() { require(msg.sender == getVoting()); _; } /** * @dev Function to be called on contract initialization * @param _consensus address of the network consensus contract */ function initialize(address _consensus) external onlyOwner { require(!isInitialized()); require(_consensus != address(0)); require(_consensus != address(this)); _setConsensus(_consensus); setInitialized(true); } /** * @dev Function to be called to initialize all available contract types addresses */ function initializeAddresses(address _blockReward, address _voting) external onlyOwner { require(!boolStorage[PROXY_STORAGE_ADDRESSES_INITIALIZED]); addressStorage[BLOCK_REWARD] = _blockReward; addressStorage[VOTING] = _voting; boolStorage[PROXY_STORAGE_ADDRESSES_INITIALIZED] = true; emit ProxyInitialized( getConsensus(), _blockReward, _voting ); } /** * @dev Function to be called to set specific contract type address * @param _contractType contract type (See ContractTypes enum) * @param _contractAddress contract address set for the contract type */ function setContractAddress(uint256 _contractType, address _contractAddress) external onlyVoting returns(bool) { if (!isInitialized()) return false; if (_contractAddress == address(0)) return false; bool success = false; if (_contractType == uint256(ContractTypes.Consensus)) { success = EternalStorageProxy(getConsensus()).upgradeTo(_contractAddress); } else if (_contractType == uint256(ContractTypes.BlockReward)) { success = EternalStorageProxy(getBlockReward()).upgradeTo(_contractAddress); } else if (_contractType == uint256(ContractTypes.ProxyStorage)) { success = EternalStorageProxy(this).upgradeTo(_contractAddress); } else if (_contractType == uint256(ContractTypes.Voting)) { success = EternalStorageProxy(getVoting()).upgradeTo(_contractAddress); } if (success) { emit AddressSet(_contractType, _contractAddress); } return success; } /** * @dev Function checking if a contract type is valid one for proxy usage * @param _contractType contract type to check if valid */ function isValidContractType(uint256 _contractType) external pure returns(bool) { return _contractType == uint256(ContractTypes.Consensus) || _contractType == uint256(ContractTypes.BlockReward) || _contractType == uint256(ContractTypes.ProxyStorage) || _contractType == uint256(ContractTypes.Voting); } bytes32 internal constant OWNER = keccak256(abi.encodePacked("owner")); bytes32 internal constant CONSENSUS = keccak256(abi.encodePacked("consensus")); bytes32 internal constant BLOCK_REWARD = keccak256(abi.encodePacked("blockReward")); bytes32 internal constant VOTING = keccak256(abi.encodePacked("voting")); bytes32 internal constant PROXY_STORAGE_ADDRESSES_INITIALIZED = keccak256(abi.encodePacked("proxyStorageAddressesInitialized")); function _setConsensus(address _consensus) private { addressStorage[CONSENSUS] = _consensus; } function getConsensus() public view returns(address){ return addressStorage[CONSENSUS]; } function getBlockReward() public view returns(address){ return addressStorage[BLOCK_REWARD]; } function getVoting() public view returns(address){ return addressStorage[VOTING]; } } // File: contracts/VotingUtils.sol pragma solidity ^0.4.24; /** * @title Voting utility contract * @author LiorRabin */ contract VotingUtils is EternalStorage, VotingBase { using SafeMath for uint256; uint256 public constant DECIMALS = 10 ** 18; uint256 public constant MAX_LIMIT_OF_BALLOTS = 100; uint256 public constant MIN_BALLOT_DURATION_CYCLES = 2; uint256 public constant MAX_BALLOT_DURATION_CYCLES = 14; uint256 public constant MINIMUM_TURNOUT_BP = 2000; //20% /** * @dev This modifier verifies that msg.sender is the owner of the contract */ modifier onlyOwner() { require(msg.sender == addressStorage[OWNER]); _; } /** * @dev This modifier verifies the duration of the ballot is valid */ modifier onlyValidDuration(uint256 _startAfterNumberOfCycles, uint256 _cyclesDuration) { require(_startAfterNumberOfCycles > 0); require(_cyclesDuration > 0); require(_cyclesDuration >= getMinBallotDurationCycles()); require(_cyclesDuration <= getMaxBallotDurationCycles()); _; } /** * @dev This modifier verifies an address is valid for voting */ modifier onlyValidVotingKey(address _address) { require(isValidVotingKey(_address)); _; } /** * @dev This modifier verifies that msg.sender is the consensus contract */ modifier onlyConsensus() { require(msg.sender == ProxyStorage(getProxyStorage()).getConsensus()); _; } bytes32 internal constant OWNER = keccak256(abi.encodePacked("owner")); bytes32 internal constant NEXT_BALLOT_ID = keccak256(abi.encodePacked("nextBallotId")); bytes32 internal constant ACTIVE_BALLOTS = keccak256(abi.encodePacked("activeBallots")); bytes32 internal constant PROXY_STORAGE = keccak256(abi.encodePacked("proxyStorage")); /** * @dev Function to check if a contract type is a valid network contract * @param _contractType contract type to check (See ProxyStorage.ContractTypes) */ function validContractType(uint256 _contractType) public view returns(bool) { return ProxyStorage(getProxyStorage()).isValidContractType(_contractType); } /** * @dev This function checks if an address is valid for voting (is a validator) * @param _address the address to check if valid for voting */ function isValidVotingKey(address _address) public view returns(bool) { bool valid = false; IConsensus consensus = IConsensus(ProxyStorage(getProxyStorage()).getConsensus()); for (uint256 i; i < consensus.currentValidatorsLength(); i++) { address validator = consensus.currentValidatorsAtPosition(i); if (validator == _address) { valid = true; } } return valid; } /** * @dev Function to get the number of "open" (active) ballots each validator (someone with voting rights) can have at the same time */ function getBallotLimitPerValidator() public view returns(uint256) { uint256 validatorsCount = getTotalNumberOfValidators(); if (validatorsCount == 0) { return MAX_LIMIT_OF_BALLOTS; } uint256 limit = MAX_LIMIT_OF_BALLOTS.div(validatorsCount); if (limit == 0) { limit = 1; } return limit; } /** * @dev Function used to check if a voting key has voted on a specific ballot * @param _id ballot id to get info of * @param _key voter key to get if voted already */ function hasAlreadyVoted(uint256 _id, address _key) public view returns(bool) { if (_key == address(0)) { return false; } return getVoterChoice(_id, _key) != 0; } /** * @dev This function is used to check if a ballot can be finalized * @param _id ballot id to check */ function canBeFinalized(uint256 _id) public view returns(bool) { if (_id >= getNextBallotId()) return false; if (getStartBlock(_id) > block.number) return false; if (getIsFinalized(_id)) return false; return block.number >= getEndBlock(_id); } function getProposedValue(uint256 _id) public view returns(address) { return addressStorage[keccak256(abi.encodePacked("votingState", _id, "proposedValue"))]; } function _setProposedValue(uint256 _id, address _value) internal { addressStorage[keccak256(abi.encodePacked("votingState", _id, "proposedValue"))] = _value; } function getContractType(uint256 _id) public view returns(uint256) { return uintStorage[keccak256(abi.encodePacked("votingState", _id, "contractType"))]; } function _setContractType(uint256 _id, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("votingState", _id, "contractType"))] = _value; } /** * @dev This function is used to create a ballot * @param _startAfterNumberOfCycles number of cycles after which the ballot should open for voting * @param _cyclesDuration number of cycles the ballot will remain open for voting * @param _description ballot text description */ function _createBallot(uint256 _startAfterNumberOfCycles, uint256 _cyclesDuration, string _description) internal returns(uint256) { require(isInitialized()); address creator = msg.sender; require(withinLimit(creator)); uint256 ballotId = getNextBallotId(); _setNextBallotId(ballotId.add(1)); _setStartBlock(ballotId, _startAfterNumberOfCycles); _setEndBlock(ballotId, _cyclesDuration); _setIsFinalized(ballotId, false); _setQuorumState(ballotId, uint256(QuorumStates.InProgress)); _setCreator(ballotId, creator); _setDescription(ballotId, _description); _setIndex(ballotId, activeBallotsLength()); _setBelowTurnOut(ballotId, false); _activeBallotsAdd(ballotId); _increaseValidatorLimit(creator); emit BallotCreated(ballotId, creator); return ballotId; } function _finalize(uint256 _id) internal { if (!getFinalizeCalled(_id)) { _decreaseValidatorLimit(_id); _setFinalizeCalled(_id); } // check the turnout if (_checkTurnout(_id)) { if (getAccepted(_id) > getRejected(_id)) { if (_finalizeBallot(_id)) { _setQuorumState(_id, uint256(QuorumStates.Accepted)); } else { return; } } else { _setQuorumState(_id, uint256(QuorumStates.Rejected)); } _setBelowTurnOut(_id, false); } else { // didn't meet the turn out _setBelowTurnOut(_id, true); _setQuorumState(_id, uint256(QuorumStates.Rejected)); } _deactivateBallot(_id); _setIsFinalized(_id, true); emit BallotFinalized(_id); } function _deactivateBallot(uint256 _id) internal { uint256 removedIndex = getIndex(_id); uint256 lastIndex = activeBallotsLength() - 1; uint256 lastBallotId = activeBallotsAtIndex(lastIndex); // Override the removed ballot with the last one. _activeBallotsSet(removedIndex, lastBallotId); // Update the index of the last validator. _setIndex(lastBallotId, removedIndex); _activeBallotsSet(lastIndex, 0); _activeBallotsDecreaseLength(); } function _finalizeBallot(uint256 _id) internal returns(bool) { return ProxyStorage(getProxyStorage()).setContractAddress(getContractType(_id), getProposedValue(_id)); } function isActiveBallot(uint256 _id) public view returns(bool) { return getStartBlock(_id) < block.number && block.number < getEndBlock(_id); } function getQuorumState(uint256 _id) external view returns(uint256) { return uintStorage[keccak256(abi.encodePacked("votingState", _id, "quorumState"))]; } function _setQuorumState(uint256 _id, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("votingState", _id, "quorumState"))] = _value; } function getNextBallotId() public view returns(uint256) { return uintStorage[NEXT_BALLOT_ID]; } function _setNextBallotId(uint256 _id) internal { uintStorage[NEXT_BALLOT_ID] = _id; } /** * returns minimum number of cycles a ballot can be open before finalization */ function getMinBallotDurationCycles() public pure returns(uint256) { return MIN_BALLOT_DURATION_CYCLES; } /** * returns maximum number of cycles a ballot can be open before finalization */ function getMaxBallotDurationCycles() public pure returns(uint256) { return MAX_BALLOT_DURATION_CYCLES; } function getStartBlock(uint256 _id) public view returns(uint256) { return uintStorage[keccak256(abi.encodePacked("votingState", _id, "startBlock"))]; } function _setStartBlock(uint256 _id, uint256 _startAfterNumberOfCycles) internal { IConsensus consensus = IConsensus(ProxyStorage(getProxyStorage()).getConsensus()); uint256 cycleDurationBlocks = consensus.getCycleDurationBlocks(); uint256 currentCycleEndBlock = consensus.getCurrentCycleEndBlock(); uint256 startBlock = currentCycleEndBlock.add(_startAfterNumberOfCycles.mul(cycleDurationBlocks)); uintStorage[keccak256(abi.encodePacked("votingState", _id, "startBlock"))] = startBlock; } function getEndBlock(uint256 _id) public view returns(uint256) { return uintStorage[keccak256(abi.encodePacked("votingState", _id, "endBlock"))]; } function _setEndBlock(uint256 _id, uint256 _cyclesDuration) internal { uint256 cycleDurationBlocks = IConsensus(ProxyStorage(getProxyStorage()).getConsensus()).getCycleDurationBlocks(); uint256 startBlock = getStartBlock(_id); uint256 endBlock = startBlock.add(_cyclesDuration.mul(cycleDurationBlocks)); uintStorage[keccak256(abi.encodePacked("votingState", _id, "endBlock"))] = endBlock; } function getIsFinalized(uint256 _id) public view returns(bool) { return boolStorage[keccak256(abi.encodePacked("votingState", _id, "isFinalized"))]; } function _setIsFinalized(uint256 _id, bool _value) internal { boolStorage[keccak256(abi.encodePacked("votingState", _id, "isFinalized"))] = _value; } function getBelowTurnOut(uint256 _id) public view returns(bool) { return boolStorage[keccak256(abi.encodePacked("votingState", _id, "belowTurnOut"))]; } function _setBelowTurnOut(uint256 _id, bool _value) internal { boolStorage[keccak256(abi.encodePacked("votingState", _id, "belowTurnOut"))] = _value; } function getDescription(uint256 _id) public view returns(string) { return stringStorage[keccak256(abi.encodePacked("votingState", _id, "description"))]; } function _setDescription(uint256 _id, string _value) internal { stringStorage[keccak256(abi.encodePacked("votingState", _id, "description"))] = _value; } function getCreator(uint256 _id) public view returns(address) { return addressStorage[keccak256(abi.encodePacked("votingState", _id, "creator"))]; } function _setCreator(uint256 _id, address _value) internal { addressStorage[keccak256(abi.encodePacked("votingState", _id, "creator"))] = _value; } function getIndex(uint256 _id) public view returns(uint256) { return uintStorage[keccak256(abi.encodePacked("votingState", _id, "index"))]; } function _setIndex(uint256 _id, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("votingState", _id, "index"))] = _value; } function activeBallots() public view returns(uint[]) { return uintArrayStorage[ACTIVE_BALLOTS]; } function activeBallotsAtIndex(uint256 _index) public view returns(uint256) { return uintArrayStorage[ACTIVE_BALLOTS][_index]; } function activeBallotsLength() public view returns(uint256) { return uintArrayStorage[ACTIVE_BALLOTS].length; } function _activeBallotsAdd(uint256 _id) internal { uintArrayStorage[ACTIVE_BALLOTS].push(_id); } function _activeBallotsDecreaseLength() internal { if (activeBallotsLength() > 0) { uintArrayStorage[ACTIVE_BALLOTS].length--; } } function _activeBallotsSet(uint256 _index, uint256 _id) internal { uintArrayStorage[ACTIVE_BALLOTS][_index] = _id; } function validatorActiveBallots(address _key) public view returns(uint256) { return uintStorage[keccak256(abi.encodePacked("validatorActiveBallots", _key))]; } function _setValidatorActiveBallots(address _key, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("validatorActiveBallots", _key))] = _value; } function _increaseValidatorLimit(address _key) internal { _setValidatorActiveBallots(_key, validatorActiveBallots(_key).add(1)); } function _decreaseValidatorLimit(uint256 _id) internal { address key = getCreator(_id); uint256 ballotsCount = validatorActiveBallots(key); if (ballotsCount > 0) { _setValidatorActiveBallots(key, ballotsCount - 1); } } function getFinalizeCalled(uint256 _id) public view returns(bool) { return boolStorage[keccak256(abi.encodePacked("finalizeCalled", _id))]; } function _setFinalizeCalled(uint256 _id) internal { boolStorage[keccak256(abi.encodePacked("finalizeCalled", _id))] = true; } function getProxyStorage() public view returns(address) { return addressStorage[PROXY_STORAGE]; } function getTotalNumberOfValidators() internal view returns(uint256) { return IConsensus(ProxyStorage(getProxyStorage()).getConsensus()).currentValidatorsLength(); } function getStake(address _key) internal view returns(uint256) { return IConsensus(ProxyStorage(getProxyStorage()).getConsensus()).stakeAmount(_key); } function _setVoterChoice(uint256 _id, address _key, uint256 _choice) internal { uintStorage[keccak256(abi.encodePacked("votingState", _id, "voters", _key))] = _choice; } function getVoterChoice(uint256 _id, address _key) public view returns(uint256) { return uintStorage[keccak256(abi.encodePacked("votingState", _id, "voters", _key))]; } function withinLimit(address _key) internal view returns(bool) { return validatorActiveBallots(_key) < getBallotLimitPerValidator(); } function getAccepted(uint256 _id) public view returns(uint256) { return uintStorage[keccak256(abi.encodePacked("votingState", _id, "accepted"))]; } function _setAccepted(uint256 _id, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("votingState", _id, "accepted"))] = _value; } function getRejected(uint256 _id) public view returns(uint256) { return uintStorage[keccak256(abi.encodePacked("votingState", _id, "rejected"))]; } function _setRejected(uint256 _id, uint256 _value) internal { uintStorage[keccak256(abi.encodePacked("votingState", _id, "rejected"))] = _value; } function getTotalStake(uint256 _id) public view returns(uint256) { return uintStorage[keccak256(abi.encodePacked("votingState", _id, "totalStake"))]; } function _setTotalStake(uint256 _id) internal { uintStorage[keccak256(abi.encodePacked("votingState", _id, "totalStake"))] = IConsensus(ProxyStorage(getProxyStorage()).getConsensus()).totalStakeAmount(); } function _checkTurnout(uint256 _id) internal view returns(bool) { uint256 stake = getTotalStake(_id); uint256 minTurnout = stake * MINIMUM_TURNOUT_BP / 10000; uint256 totalVotedFor = getAccepted(_id); return totalVotedFor > minTurnout; } } // File: contracts/Voting.sol pragma solidity ^0.4.24; /** * @title Contract handling vote to change implementations network contracts * @author LiorRabin */ contract Voting is VotingUtils { /** * @dev Function to be called on contract initialization */ function initialize() external onlyOwner { require(!isInitialized()); setInitialized(true); } /** * @dev Function to create a new ballot * @param _startAfterNumberOfCycles number of cycles after which the ballot should open for voting * @param _cyclesDuration number of cycles the ballot will remain open for voting * @param _contractType contract type to change its address (See ProxyStorage.ContractTypes) * @param _proposedValue proposed address for the contract type * @param _description ballot text description */ function newBallot(uint256 _startAfterNumberOfCycles, uint256 _cyclesDuration, uint256 _contractType, address _proposedValue, string _description) external onlyValidVotingKey(msg.sender) onlyValidDuration(_startAfterNumberOfCycles, _cyclesDuration) returns(uint256) { require(_proposedValue != address(0)); require(validContractType(_contractType)); uint256 ballotId = _createBallot(_startAfterNumberOfCycles, _cyclesDuration, _description); _setProposedValue(ballotId, _proposedValue); _setContractType(ballotId, _contractType); return ballotId; } /** * @dev Function to get specific ballot info along with voters involvment on it * @param _id ballot id to get info of * @param _key voter key to get if voted already */ function getBallotInfo(uint256 _id, address _key) external view returns(uint256 startBlock, uint256 endBlock, bool isFinalized, address proposedValue, uint256 contractType, address creator, string description, bool canBeFinalizedNow, bool alreadyVoted, bool belowTurnOut, uint256 accepted, uint256 rejected, uint256 totalStake) { startBlock = getStartBlock(_id); endBlock = getEndBlock(_id); isFinalized = getIsFinalized(_id); proposedValue = getProposedValue(_id); contractType = getContractType(_id); creator = getCreator(_id); description = getDescription(_id); canBeFinalizedNow = canBeFinalized(_id); alreadyVoted = hasAlreadyVoted(_id, _key); belowTurnOut = getBelowTurnOut(_id); accepted = getAccepted(_id); rejected = getRejected(_id); totalStake = getTotalStake(_id); return (startBlock, endBlock, isFinalized, proposedValue, contractType, creator, description, canBeFinalizedNow, alreadyVoted, belowTurnOut, accepted, rejected, totalStake); } /** * @dev This function is used to vote on a ballot * @param _id ballot id to vote on * @param _choice voting decision on the ballot (see VotingBase.ActionChoices) */ function vote(uint256 _id, uint256 _choice) external { require(!getIsFinalized(_id)); address voter = msg.sender; require(isActiveBallot(_id)); require(!hasAlreadyVoted(_id, voter)); require(_choice == uint(ActionChoices.Accept) || _choice == uint(ActionChoices.Reject)); _setVoterChoice(_id, voter, _choice); emit Vote(_id, _choice, voter); } /** * @dev Function to be called by the consensus contract when a cycles ends * In this function, all active ballots votes will be counted and updated according to the current validators */ function onCycleEnd(address[] validators) external onlyConsensus { uint256 numOfValidators = validators.length; if (numOfValidators == 0) { return; } uint[] memory ballots = activeBallots(); for (uint256 i = 0; i < ballots.length; i++) { uint256 ballotId = ballots[i]; if (getStartBlock(ballotId) < block.number && !getFinalizeCalled(ballotId)) { if (canBeFinalized(ballotId)) { uint256 accepts = 0; uint256 rejects = 0; for (uint256 j = 0; j < numOfValidators; j++) { uint256 choice = getVoterChoice(ballotId, validators[j]); if (choice == uint(ActionChoices.Accept)) { accepts = accepts.add(getStake(validators[j])); } else if (choice == uint256(ActionChoices.Reject)) { rejects = rejects.add(getStake(validators[j])); } } _setAccepted(ballotId, accepts); _setRejected(ballotId, rejects); _setTotalStake(ballotId); _finalize(ballotId); } } } } }
Contract ABI
[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getStartBlock","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getQuorumState","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"MIN_BALLOT_DURATION_CYCLES","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getVoterChoice","inputs":[{"type":"uint256","name":"_id"},{"type":"address","name":"_key"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getAccepted","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"getIsFinalized","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isActiveBallot","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"getFinalizeCalled","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"DECIMALS","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"MINIMUM_TURNOUT_BP","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isInitialized","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getNextBallotId","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getTotalStake","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"MAX_BALLOT_DURATION_CYCLES","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":""}],"name":"getDescription","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"getBelowTurnOut","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getRejected","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"activeBallotsLength","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isValidVotingKey","inputs":[{"type":"address","name":"_address"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"canBeFinalized","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"MAX_LIMIT_OF_BALLOTS","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getMaxBallotDurationCycles","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"startBlock"},{"type":"uint256","name":"endBlock"},{"type":"bool","name":"isFinalized"},{"type":"address","name":"proposedValue"},{"type":"uint256","name":"contractType"},{"type":"address","name":"creator"},{"type":"string","name":"description"},{"type":"bool","name":"canBeFinalizedNow"},{"type":"bool","name":"alreadyVoted"},{"type":"bool","name":"belowTurnOut"},{"type":"uint256","name":"accepted"},{"type":"uint256","name":"rejected"},{"type":"uint256","name":"totalStake"}],"name":"getBallotInfo","inputs":[{"type":"uint256","name":"_id"},{"type":"address","name":"_key"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getEndBlock","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getIndex","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"vote","inputs":[{"type":"uint256","name":"_id"},{"type":"uint256","name":"_choice"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"onCycleEnd","inputs":[{"type":"address[]","name":"validators"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getContractType","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"newBallot","inputs":[{"type":"uint256","name":"_startAfterNumberOfCycles"},{"type":"uint256","name":"_cyclesDuration"},{"type":"uint256","name":"_contractType"},{"type":"address","name":"_proposedValue"},{"type":"string","name":"_description"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"hasAlreadyVoted","inputs":[{"type":"uint256","name":"_id"},{"type":"address","name":"_key"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":""}],"name":"activeBallots","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getCreator","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getProposedValue","inputs":[{"type":"uint256","name":"_id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"activeBallotsAtIndex","inputs":[{"type":"uint256","name":"_index"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getProxyStorage","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"validContractType","inputs":[{"type":"uint256","name":"_contractType"}],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getMinBallotDurationCycles","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"validatorActiveBallots","inputs":[{"type":"address","name":"_key"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getBallotLimitPerValidator","inputs":[],"constant":true},{"type":"event","name":"BallotCreated","inputs":[{"type":"uint256","name":"id","indexed":true},{"type":"address","name":"creator","indexed":true}],"anonymous":false},{"type":"event","name":"BallotFinalized","inputs":[{"type":"uint256","name":"id","indexed":true}],"anonymous":false},{"type":"event","name":"Vote","inputs":[{"type":"uint256","name":"id","indexed":true},{"type":"uint256","name":"decision","indexed":false},{"type":"address","name":"voter","indexed":true}],"anonymous":false}]
Contract Creation Code
0x608060405234801561001057600080fd5b506138f2806100206000396000f3006080604052600436106101d45763ffffffff60e060020a60003504166301b2320e81146101d957806308dbb18e146102035780630af58e771461021b5780630eac27f41461023057806322e5fe9d1461025457806323e1a0a81461026c5780632b592f92146102985780632dfba528146102b05780632e0f2625146102c8578063340d3dc2146102dd578063392e53cd146102f25780633ee2f2121461030757806345367f231461031c578063480ca380146103345780634925ec551461034957806360970b6f146103d657806362f4c26b146103ee5780636ccc02341461040657806377da79301461041b5780638129fc1c1461043c57806382c4c96314610453578063897ba3e41461046b5780638be774d3146104805780638c64a20d146104955780638c8ab7ad146105b95780638e7cb6e1146105d1578063b384abef146105e9578063bbac62c814610604578063bdd4ae5514610624578063c12eefd21461063c578063c14bfd2914610675578063d21dc68a14610699578063d48e638a146106fe578063d6edcb3814610732578063df0444771461074a578063ec15a5e614610762578063edaab22314610777578063f3161a4d1461078f578063f49774ee146107a4578063fcff021c146107c5575b600080fd5b3480156101e557600080fd5b506101f16004356107da565b60408051918252519081900360200190f35b34801561020f57600080fd5b506101f16004356108b0565b34801561022757600080fd5b506101f1610942565b34801561023c57600080fd5b506101f1600435600160a060020a0360243516610947565b34801561026057600080fd5b506101f1600435610a39565b34801561027857600080fd5b50610284600435610acb565b604080519115158252519081900360200190f35b3480156102a457600080fd5b50610284600435610ba2565b3480156102bc57600080fd5b50610284600435610bc7565b3480156102d457600080fd5b506101f1610c43565b3480156102e957600080fd5b506101f1610c4f565b3480156102fe57600080fd5b50610284610c55565b34801561031357600080fd5b506101f1610d0e565b34801561032857600080fd5b506101f1600435610dc3565b34801561034057600080fd5b506101f1610e55565b34801561035557600080fd5b50610361600435610e5a565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561039b578181015183820152602001610383565b50505050905090810190601f1680156103c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103e257600080fd5b50610284600435610fd0565b3480156103fa57600080fd5b506101f1600435611062565b34801561041257600080fd5b506101f16110f4565b34801561042757600080fd5b50610284600160a060020a0360043516611156565b34801561044857600080fd5b506104516112e6565b005b34801561045f57600080fd5b506102846004356113c8565b34801561047757600080fd5b506101f1611420565b34801561048c57600080fd5b506101f1611425565b3480156104a157600080fd5b506104b9600435600160a060020a036024351661142a565b604051808e81526020018d81526020018c1515151581526020018b600160a060020a0316600160a060020a031681526020018a815260200189600160a060020a0316600160a060020a0316815260200180602001881515151581526020018715151515815260200186151515158152602001858152602001848152602001838152602001828103825289818151815260200191508051906020019080838360005b8381101561057257818101518382015260200161055a565b50505050905090810190601f16801561059f5780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060405180910390f35b3480156105c557600080fd5b506101f16004356114e0565b3480156105dd57600080fd5b506101f1600435611572565b3480156105f557600080fd5b50610451600435602435611604565b34801561061057600080fd5b5061045160048035602481019101356116ad565b34801561063057600080fd5b506101f16004356118a3565b34801561064857600080fd5b506101f16004803590602480359160443591600160a060020a036064351691608435918201910135611935565b34801561068157600080fd5b50610284600435600160a060020a0360243516611a1a565b3480156106a557600080fd5b506106ae611a47565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156106ea5781810151838201526020016106d2565b505050509050019250505060405180910390f35b34801561070a57600080fd5b50610716600435611b34565b60408051600160a060020a039092168252519081900360200190f35b34801561073e57600080fd5b50610716600435611c11565b34801561075657600080fd5b506101f1600435611ca3565b34801561076e57600080fd5b50610716611d61565b34801561078357600080fd5b50610284600435611e1f565b34801561079b57600080fd5b506101f1611ea3565b3480156107b057600080fd5b506101f1600160a060020a0360043516611ea8565b3480156107d157600080fd5b506101f1611f45565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f7374617274426c6f636b00000000000000000000000000000000000000000000815250600a019150506040516020818303038152906040526040518082805190602001908083835b6020831061086d5780518252601f19909201916020918201910161084e565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205493505050505b919050565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f71756f72756d5374617465000000000000000000000000000000000000000000815250600b019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b600281565b604080516000805160206138a7833981519152602080830191909152602b82018590527f766f746572730000000000000000000000000000000000000000000000000000604b8301526c01000000000000000000000000600160a060020a0385160260518301528251604581840301815260659092019283905281516000936002938593909282918401908083835b602083106109f55780518252601f1990920191602091820191016109d6565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205493505050505b92915050565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f61636365707465640000000000000000000000000000000000000000000000008152506008019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b6000600660008360405160200180806000805160206138a7833981519152815250600b01828152602001807f697346696e616c697a6564000000000000000000000000000000000000000000815250600b019150506040516020818303038152906040526040518082805190602001908083835b60208310610b5e5780518252601f199092019160209182019101610b3f565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b600043610bae836107da565b108015610a335750610bbf826114e0565b431092915050565b6000600660008360405160200180807f66696e616c697a6543616c6c6564000000000000000000000000000000000000815250600e0182815260200191505060405160208183030381529060405260405180828051906020019080838360208310610b5e5780518252601f199092019160209182019101610b3f565b670de0b6b3a764000081565b6107d081565b60006006600060405160200180807f6973496e697469616c697a656400000000000000000000000000000000000000815250600d0190506040516020818303038152906040526040518082805190602001908083835b60208310610cca5780518252601f199092019160209182019101610cab565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1693505050505b90565b60006002600060405160200180807f6e65787442616c6c6f7449640000000000000000000000000000000000000000815250600c0190506040516020818303038152906040526040518082805190602001908083835b60208310610d835780518252601f199092019160209182019101610d64565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054949350505050565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f746f74616c5374616b6500000000000000000000000000000000000000000000815250600a019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b600e81565b6060600360008360405160200180806000805160206138a7833981519152815250600b01828152602001807f6465736372697074696f6e000000000000000000000000000000000000000000815250600b019150506040516020818303038152906040526040518082805190602001908083835b60208310610eed5780518252601f199092019160209182019101610ece565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610fc45780601f10610f9957610100808354040283529160200191610fc4565b820191906000526020600020905b815481529060010190602001808311610fa757829003601f168201915b50505050509050919050565b6000600660008360405160200180806000805160206138a7833981519152815250600b01828152602001807f62656c6f775475726e4f75740000000000000000000000000000000000000000815250600c0191505060405160208183030381529060405260405180828051906020019080838360208310610b5e5780518252601f199092019160209182019101610b3f565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f72656a65637465640000000000000000000000000000000000000000000000008152506008019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b6000600860006040516020018080600080516020613887833981519152815250600d01905060405160208183030381529060405260405180828051906020019080838360208310610d835780518252601f199092019160209182019101610d64565b600080808080611164611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156111a157600080fd5b505af11580156111b5573d6000803e3d6000fd5b505050506040513d60208110156111cb57600080fd5b505192505b82600160a060020a03166340c9cdeb6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561120e57600080fd5b505af1158015611222573d6000803e3d6000fd5b505050506040513d602081101561123857600080fd5b50518210156112dc5782600160a060020a03166357aeefc5836040518263ffffffff1660e060020a02815260040180828152602001915050602060405180830381600087803b15801561128a57600080fd5b505af115801561129e573d6000803e3d6000fd5b505050506040513d60208110156112b457600080fd5b50519050600160a060020a0380821690871614156112d157600193505b6001909101906111d0565b5091949350505050565b6004600060405160200180807f6f776e657200000000000000000000000000000000000000000000000000000081525060050190506040516020818303038152906040526040518082805190602001908083835b602083106113595780518252601f19909201916020918201910161133a565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a0316331492506113aa91505057600080fd5b6113b2610c55565b156113bc57600080fd5b6113c66001611f8b565b565b60006113d2610d0e565b82106113e0575060006108ab565b436113ea836107da565b11156113f8575060006108ab565b61140182610acb565b1561140e575060006108ab565b611417826114e0565b43101592915050565b606481565b600e90565b60008060008060008060606000806000806000806114478f6107da565b9c506114528f6114e0565b9b5061145d8f610acb565b9a506114688f611c11565b99506114738f6118a3565b985061147e8f611b34565b97506114898f610e5a565b96506114948f6113c8565b95506114a08f8f611a1a565b94506114ab8f610fd0565b93506114b68f610a39565b92506114c18f611062565b91506114cc8f610dc3565b90509295989b9e9194979a9d509295989b50565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f656e64426c6f636b0000000000000000000000000000000000000000000000008152506008019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f696e6465780000000000000000000000000000000000000000000000000000008152506005019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b600061160f83610acb565b1561161957600080fd5b503361162483610ba2565b151561162f57600080fd5b6116398382611a1a565b1561164357600080fd5b60018214806116525750600282145b151561165d57600080fd5b61166883828461204c565b604080518381529051600160a060020a0383169185917f7c2f48a4bf2e759e77b1e77a8bf1034cdf16e9034dad596d3655bb8b315f85eb9181900360200190a3505050565b600060606000806000806000806116c2611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156116ff57600080fd5b505af1158015611713573d6000803e3d6000fd5b505050506040513d602081101561172957600080fd5b5051600160a060020a0316331461173f57600080fd5b88975087151561174e57611897565b611756611a47565b9650600095505b865186101561189757868681518110151561177457fe5b9060200190602002015194504361178a866107da565b10801561179d575061179b85610bc7565b155b1561188c576117ab856113c8565b1561188c576000935060009250600091505b87821015611866576117ea858b8b858181106117d557fe5b90506020020135600160a060020a0316610947565b905060018114156118305761182961181c8b8b8581811061180757fe5b90506020020135600160a060020a031661213d565b859063ffffffff61221516565b935061185b565b600281141561185b5761185861184b8b8b8581811061180757fe5b849063ffffffff61221516565b92505b6001909101906117bd565b6118708585612232565b61187a8584612306565b61188385612397565b61188c85612561565b60019095019461175d565b50505050505050505050565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f636f6e7472616374547970650000000000000000000000000000000000000000815250600c019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b6000803361194281611156565b151561194d57600080fd5b88886000821161195c57600080fd5b6000811161196957600080fd5b611971611ea3565b81101561197d57600080fd5b611985611425565b81111561199157600080fd5b600160a060020a03881615156119a657600080fd5b6119af89611e1f565b15156119ba57600080fd5b6119f58b8b89898080601f01602080910402602001604051908101604052809392919081815260200183838082843750612645945050505050565b9350611a018489612742565b611a0b848a61283e565b50919998505050505050505050565b6000600160a060020a0382161515611a3457506000610a33565b611a3e8383610947565b15159392505050565b6060600860006040516020018080600080516020613887833981519152815250600d0190506040516020818303038152906040526040518082805190602001908083835b60208310611aaa5780518252601f199092019160209182019101611a8b565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652858101969096525092830160002080548451818702810187019095528085529394909392508401905082828015611b2a57602002820191906000526020600020905b815481526020019060010190808311611b16575b5050505050905090565b6000600460008360405160200180806000805160206138a7833981519152815250600b01828152602001807f63726561746f72000000000000000000000000000000000000000000000000008152506007019150506040516020818303038152906040526040518082805190602001908083835b60208310611bc75780518252601f199092019160209182019101611ba8565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a031695945050505050565b6000600460008360405160200180806000805160206138a7833981519152815250600b01828152602001807f70726f706f73656456616c756500000000000000000000000000000000000000815250600d0191505060405160208183030381529060405260405180828051906020019080838360208310611bc75780518252601f199092019160209182019101611ba8565b6000600860006040516020018080600080516020613887833981519152815250600d0190506040516020818303038152906040526040518082805190602001908083835b60208310611d065780518252601f199092019160209182019101611ce7565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805490935085925082109050611d4f57fe5b90600052602060002001549050919050565b60006004600060405160200180807f70726f787953746f726167650000000000000000000000000000000000000000815250600c0190506040516020818303038152906040526040518082805190602001908083835b60208310611dd65780518252601f199092019160209182019101611db7565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a0316949350505050565b6000611e29611d61565b600160a060020a03166333875fdd836040518263ffffffff1660e060020a02815260040180828152602001915050602060405180830381600087803b158015611e7157600080fd5b505af1158015611e85573d6000803e3d6000fd5b505050506040513d6020811015611e9b57600080fd5b505192915050565b600290565b6000600260008360405160200180807f76616c696461746f7241637469766542616c6c6f74730000000000000000000081525060160182600160a060020a0316600160a060020a03166c010000000000000000000000000281526014019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b6000806000611f526128cf565b9150811515611f645760649250611f86565b611f7560648363ffffffff6129d016565b9050801515611f82575060015b8092505b505090565b806006600060405160200180807f6973496e697469616c697a656400000000000000000000000000000000000000815250600d0190506040516020818303038152906040526040518082805190602001908083835b60208310611fff5780518252601f199092019160209182019101611fe0565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff19169415159490941790935550505050565b604080516000805160206138a7833981519152602080830191909152602b82018690527f766f746572730000000000000000000000000000000000000000000000000000604b8301526c01000000000000000000000000600160a060020a0386160260518301528251604581840301815260659092019283905281518493600293600093909282918401908083835b602083106120fa5780518252601f1990920191602091820191016120db565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002093909355505050505050565b6000612147611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561218457600080fd5b505af1158015612198573d6000803e3d6000fd5b505050506040513d60208110156121ae57600080fd5b5051604080517fbf135267000000000000000000000000000000000000000000000000000000008152600160a060020a0385811660048301529151919092169163bf1352679160248083019260209291908290030181600087803b158015611e7157600080fd5b60008282018381101561222757600080fd5b8091505b5092915050565b80600260008460405160200180806000805160206138a7833981519152815250600b01828152602001807f61636365707465640000000000000000000000000000000000000000000000008152506008019150506040516020818303038152906040526040518082805190602001908083835b602083106122c45780518252601f1990920191602091820191016122a5565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b80600260008460405160200180806000805160206138a7833981519152815250600b01828152602001807f72656a6563746564000000000000000000000000000000000000000000000000815250600801915050604051602081830303815290604052604051808280519060200190808383602083106122c45780518252601f1990920191602091820191016122a5565b61239f611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156123dc57600080fd5b505af11580156123f0573d6000803e3d6000fd5b505050506040513d602081101561240657600080fd5b5051604080517f94409a560000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216916394409a56916004808201926020929091908290030181600087803b15801561246557600080fd5b505af1158015612479573d6000803e3d6000fd5b505050506040513d602081101561248f57600080fd5b5051604080516000805160206138a7833981519152602082810191909152602b82018590527f746f74616c5374616b6500000000000000000000000000000000000000000000604b83015282516035818403018152605590920192839052815160029360009392909182918401908083835b602083106125205780518252601f199092019160209182019101612501565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000209390935550505050565b61256a81610bc7565b151561258257612579816129f3565b61258281612a27565b61258b81612aa3565b156125ec5761259981611062565b6125a282610a39565b11156125d1576125b181612ad4565b156125c7576125c28160025b612b50565b6125cc565b612642565b6125dc565b6125dc8160036125bd565b6125e7816000612be1565b612602565b6125f7816001612be1565b6126028160036125bd565b61260b81612cc1565b612616816001612d16565b60405181907fd470bb0d3dcb39ff5a62757e0a1cdfe60f8200eba22fd0d82383630d457f868690600090a25b50565b6000806000612652610c55565b151561265d57600080fd5b33915061266982612da7565b151561267457600080fd5b61267c610d0e565b905061269761269282600163ffffffff61221516565b612dc1565b6126a18187612e34565b6126ab81866130bd565b6126b6816000612d16565b6126c18160016125bd565b6126cb81836132b5565b6126d58185613346565b6126e6816126e16110f4565b613426565b6126f1816000612be1565b6126fa816134b7565b6127038261356c565b604051600160a060020a0383169082907fe64b3864f6f22f8969f8cb16c039eaf6454ef5e23c09791df010163000a7023590600090a395945050505050565b80600460008460405160200180806000805160206138a7833981519152815250600b01828152602001807f70726f706f73656456616c756500000000000000000000000000000000000000815250600d019150506040516020818303038152906040526040518082805190602001908083835b602083106127d45780518252601f1990920191602091820191016127b5565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0395909516949094179093555050505050565b80600260008460405160200180806000805160206138a7833981519152815250600b01828152602001807f636f6e7472616374547970650000000000000000000000000000000000000000815250600c01915050604051602081830303815290604052604051808280519060200190808383602083106122c45780518252601f1990920191602091820191016122a5565b60006128d9611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561291657600080fd5b505af115801561292a573d6000803e3d6000fd5b505050506040513d602081101561294057600080fd5b5051604080517f40c9cdeb0000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216916340c9cdeb916004808201926020929091908290030181600087803b15801561299f57600080fd5b505af11580156129b3573d6000803e3d6000fd5b505050506040513d60208110156129c957600080fd5b5051905090565b6000808083116129df57600080fd5b82848115156129ea57fe5b04949350505050565b6000806129ff83611b34565b9150612a0a82611ea8565b90506000811115612a2257612a22826001830361358a565b505050565b6001600660008360405160200180807f66696e616c697a6543616c6c6564000000000000000000000000000000000000815250600e0182815260200191505060405160208183030381529060405260405180828051906020019080838360208310611fff5780518252601f199092019160209182019101611fe0565b600080600080612ab285610dc3565b92506127106107d08402049150612ac885610a39565b91909111949350505050565b6000612ade611d61565b600160a060020a031663bb0165b1612af5846118a3565b612afe85611c11565b6040518363ffffffff1660e060020a0281526004018083815260200182600160a060020a0316600160a060020a0316815260200192505050602060405180830381600087803b158015611e7157600080fd5b80600260008460405160200180806000805160206138a7833981519152815250600b01828152602001807f71756f72756d5374617465000000000000000000000000000000000000000000815250600b01915050604051602081830303815290604052604051808280519060200190808383602083106122c45780518252601f1990920191602091820191016122a5565b80600660008460405160200180806000805160206138a7833981519152815250600b01828152602001807f62656c6f775475726e4f75740000000000000000000000000000000000000000815250600c019150506040516020818303038152906040526040518082805190602001908083835b60208310612c735780518252601f199092019160209182019101612c54565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff1916941515949094179093555050505050565b6000806000612ccf84611572565b92506001612cdb6110f4565b039150612ce782611ca3565b9050612cf38382613626565b612cfd8184613426565b612d08826000613626565b612d106136e1565b50505050565b80600660008460405160200180806000805160206138a7833981519152815250600b01828152602001807f697346696e616c697a6564000000000000000000000000000000000000000000815250600b0191505060405160208183030381529060405260405180828051906020019080838360208310612c735780518252601f199092019160209182019101612c54565b6000612db1611f45565b612dba83611ea8565b1092915050565b806002600060405160200180807f6e65787442616c6c6f7449640000000000000000000000000000000000000000815250600c019050604051602081830303815290604052604051808280519060200190808383602083106125205780518252601f199092019160209182019101612501565b600080600080612e42611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015612e7f57600080fd5b505af1158015612e93573d6000803e3d6000fd5b505050506040513d6020811015612ea957600080fd5b5051604080517fa65249230000000000000000000000000000000000000000000000000000000081529051919550600160a060020a0386169163a6524923916004808201926020929091908290030181600087803b158015612f0a57600080fd5b505af1158015612f1e573d6000803e3d6000fd5b505050506040513d6020811015612f3457600080fd5b5051604080517faf2951810000000000000000000000000000000000000000000000000000000081529051919450600160a060020a0386169163af295181916004808201926020929091908290030181600087803b158015612f9557600080fd5b505af1158015612fa9573d6000803e3d6000fd5b505050506040513d6020811015612fbf57600080fd5b50519150612fe3612fd6868563ffffffff6137a016565b839063ffffffff61221516565b905080600260008860405160200180806000805160206138a7833981519152815250600b01828152602001807f7374617274426c6f636b00000000000000000000000000000000000000000000815250600a019150506040516020818303038152906040526040518082805190602001908083835b602083106130775780518252601f199092019160209182019101613058565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002093909355505050505050505050565b60008060006130ca611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561310757600080fd5b505af115801561311b573d6000803e3d6000fd5b505050506040513d602081101561313157600080fd5b5051604080517fa65249230000000000000000000000000000000000000000000000000000000081529051600160a060020a039092169163a6524923916004808201926020929091908290030181600087803b15801561319057600080fd5b505af11580156131a4573d6000803e3d6000fd5b505050506040513d60208110156131ba57600080fd5b505192506131c7856107da565b91506131dc612fd6858563ffffffff6137a016565b905080600260008760405160200180806000805160206138a7833981519152815250600b01828152602001807f656e64426c6f636b0000000000000000000000000000000000000000000000008152506008019150506040516020818303038152906040526040518082805190602001908083835b602083106132705780518252601f199092019160209182019101613251565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050505050565b80600460008460405160200180806000805160206138a7833981519152815250600b01828152602001807f63726561746f7200000000000000000000000000000000000000000000000000815250600701915050604051602081830303815290604052604051808280519060200190808383602083106127d45780518252601f1990920191602091820191016127b5565b80600360008460405160200180806000805160206138a7833981519152815250600b01828152602001807f6465736372697074696f6e000000000000000000000000000000000000000000815250600b019150506040516020818303038152906040526040518082805190602001908083835b602083106133d85780518252601f1990920191602091820191016133b9565b51815160001960209485036101000a01908116901991909116179052604080519490920184900390932086528583019690965250929093016000208451612a229591945092019190506137ce565b80600260008460405160200180806000805160206138a7833981519152815250600b01828152602001807f696e646578000000000000000000000000000000000000000000000000000000815250600501915050604051602081830303815290604052604051808280519060200190808383602083106122c45780518252601f1990920191602091820191016122a5565b600860006040516020018080600080516020613887833981519152815250600d0190506040516020818303038152906040526040518082805190602001908083835b602083106135185780518252601f1990920191602091820191016134f9565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285810196909652509290920160009081208054600181018255908252939020909201929092555050565b6126428161358a600161357e85611ea8565b9063ffffffff61221516565b80600260008460405160200180807f76616c696461746f7241637469766542616c6c6f74730000000000000000000081525060160182600160a060020a0316600160a060020a03166c01000000000000000000000000028152601401915050604051602081830303815290604052604051808280519060200190808383602083106122c45780518252601f1990920191602091820191016122a5565b80600860006040516020018080600080516020613887833981519152815250600d0190506040516020818303038152906040526040518082805190602001908083835b602083106136885780518252601f199092019160209182019101613669565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000208054909350869250821090506136d157fe5b6000918252602090912001555050565b60006136eb6110f4565b11156113c657600860006040516020018080600080516020613887833981519152815250600d0190506040516020818303038152906040526040518082805190602001908083835b602083106137525780518252601f199092019160209182019101613733565b51815160001960209485036101000a8101918216911992909216179091526040805195909301859003909420875286019690965250929093016000208054935061264292909150830161384c565b6000808315156137b3576000915061222b565b508282028284828115156137c357fe5b041461222757600080fd5b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061380f57805160ff191683800117855561383c565b8280016001018555821561383c579182015b8281111561383c578251825591602001919060010190613821565b5061384892915061386c565b5090565b815481835581811115612a2257600083815260209020612a229181019083015b610d0b91905b808211156138485760008155600101613872560061637469766542616c6c6f747300000000000000000000000000000000000000766f74696e675374617465000000000000000000000000000000000000000000a165627a7a723058208d70072ebed43198b496d8e8560f428fa5f8fefd60a01bc2bd679521aeb93a290029
Deployed ByteCode
0x6080604052600436106101d45763ffffffff60e060020a60003504166301b2320e81146101d957806308dbb18e146102035780630af58e771461021b5780630eac27f41461023057806322e5fe9d1461025457806323e1a0a81461026c5780632b592f92146102985780632dfba528146102b05780632e0f2625146102c8578063340d3dc2146102dd578063392e53cd146102f25780633ee2f2121461030757806345367f231461031c578063480ca380146103345780634925ec551461034957806360970b6f146103d657806362f4c26b146103ee5780636ccc02341461040657806377da79301461041b5780638129fc1c1461043c57806382c4c96314610453578063897ba3e41461046b5780638be774d3146104805780638c64a20d146104955780638c8ab7ad146105b95780638e7cb6e1146105d1578063b384abef146105e9578063bbac62c814610604578063bdd4ae5514610624578063c12eefd21461063c578063c14bfd2914610675578063d21dc68a14610699578063d48e638a146106fe578063d6edcb3814610732578063df0444771461074a578063ec15a5e614610762578063edaab22314610777578063f3161a4d1461078f578063f49774ee146107a4578063fcff021c146107c5575b600080fd5b3480156101e557600080fd5b506101f16004356107da565b60408051918252519081900360200190f35b34801561020f57600080fd5b506101f16004356108b0565b34801561022757600080fd5b506101f1610942565b34801561023c57600080fd5b506101f1600435600160a060020a0360243516610947565b34801561026057600080fd5b506101f1600435610a39565b34801561027857600080fd5b50610284600435610acb565b604080519115158252519081900360200190f35b3480156102a457600080fd5b50610284600435610ba2565b3480156102bc57600080fd5b50610284600435610bc7565b3480156102d457600080fd5b506101f1610c43565b3480156102e957600080fd5b506101f1610c4f565b3480156102fe57600080fd5b50610284610c55565b34801561031357600080fd5b506101f1610d0e565b34801561032857600080fd5b506101f1600435610dc3565b34801561034057600080fd5b506101f1610e55565b34801561035557600080fd5b50610361600435610e5a565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561039b578181015183820152602001610383565b50505050905090810190601f1680156103c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103e257600080fd5b50610284600435610fd0565b3480156103fa57600080fd5b506101f1600435611062565b34801561041257600080fd5b506101f16110f4565b34801561042757600080fd5b50610284600160a060020a0360043516611156565b34801561044857600080fd5b506104516112e6565b005b34801561045f57600080fd5b506102846004356113c8565b34801561047757600080fd5b506101f1611420565b34801561048c57600080fd5b506101f1611425565b3480156104a157600080fd5b506104b9600435600160a060020a036024351661142a565b604051808e81526020018d81526020018c1515151581526020018b600160a060020a0316600160a060020a031681526020018a815260200189600160a060020a0316600160a060020a0316815260200180602001881515151581526020018715151515815260200186151515158152602001858152602001848152602001838152602001828103825289818151815260200191508051906020019080838360005b8381101561057257818101518382015260200161055a565b50505050905090810190601f16801561059f5780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060405180910390f35b3480156105c557600080fd5b506101f16004356114e0565b3480156105dd57600080fd5b506101f1600435611572565b3480156105f557600080fd5b50610451600435602435611604565b34801561061057600080fd5b5061045160048035602481019101356116ad565b34801561063057600080fd5b506101f16004356118a3565b34801561064857600080fd5b506101f16004803590602480359160443591600160a060020a036064351691608435918201910135611935565b34801561068157600080fd5b50610284600435600160a060020a0360243516611a1a565b3480156106a557600080fd5b506106ae611a47565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156106ea5781810151838201526020016106d2565b505050509050019250505060405180910390f35b34801561070a57600080fd5b50610716600435611b34565b60408051600160a060020a039092168252519081900360200190f35b34801561073e57600080fd5b50610716600435611c11565b34801561075657600080fd5b506101f1600435611ca3565b34801561076e57600080fd5b50610716611d61565b34801561078357600080fd5b50610284600435611e1f565b34801561079b57600080fd5b506101f1611ea3565b3480156107b057600080fd5b506101f1600160a060020a0360043516611ea8565b3480156107d157600080fd5b506101f1611f45565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f7374617274426c6f636b00000000000000000000000000000000000000000000815250600a019150506040516020818303038152906040526040518082805190602001908083835b6020831061086d5780518252601f19909201916020918201910161084e565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205493505050505b919050565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f71756f72756d5374617465000000000000000000000000000000000000000000815250600b019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b600281565b604080516000805160206138a7833981519152602080830191909152602b82018590527f766f746572730000000000000000000000000000000000000000000000000000604b8301526c01000000000000000000000000600160a060020a0385160260518301528251604581840301815260659092019283905281516000936002938593909282918401908083835b602083106109f55780518252601f1990920191602091820191016109d6565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205493505050505b92915050565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f61636365707465640000000000000000000000000000000000000000000000008152506008019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b6000600660008360405160200180806000805160206138a7833981519152815250600b01828152602001807f697346696e616c697a6564000000000000000000000000000000000000000000815250600b019150506040516020818303038152906040526040518082805190602001908083835b60208310610b5e5780518252601f199092019160209182019101610b3f565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1695945050505050565b600043610bae836107da565b108015610a335750610bbf826114e0565b431092915050565b6000600660008360405160200180807f66696e616c697a6543616c6c6564000000000000000000000000000000000000815250600e0182815260200191505060405160208183030381529060405260405180828051906020019080838360208310610b5e5780518252601f199092019160209182019101610b3f565b670de0b6b3a764000081565b6107d081565b60006006600060405160200180807f6973496e697469616c697a656400000000000000000000000000000000000000815250600d0190506040516020818303038152906040526040518082805190602001908083835b60208310610cca5780518252601f199092019160209182019101610cab565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000205460ff1693505050505b90565b60006002600060405160200180807f6e65787442616c6c6f7449640000000000000000000000000000000000000000815250600c0190506040516020818303038152906040526040518082805190602001908083835b60208310610d835780518252601f199092019160209182019101610d64565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054949350505050565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f746f74616c5374616b6500000000000000000000000000000000000000000000815250600a019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b600e81565b6060600360008360405160200180806000805160206138a7833981519152815250600b01828152602001807f6465736372697074696f6e000000000000000000000000000000000000000000815250600b019150506040516020818303038152906040526040518082805190602001908083835b60208310610eed5780518252601f199092019160209182019101610ece565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610fc45780601f10610f9957610100808354040283529160200191610fc4565b820191906000526020600020905b815481529060010190602001808311610fa757829003601f168201915b50505050509050919050565b6000600660008360405160200180806000805160206138a7833981519152815250600b01828152602001807f62656c6f775475726e4f75740000000000000000000000000000000000000000815250600c0191505060405160208183030381529060405260405180828051906020019080838360208310610b5e5780518252601f199092019160209182019101610b3f565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f72656a65637465640000000000000000000000000000000000000000000000008152506008019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b6000600860006040516020018080600080516020613887833981519152815250600d01905060405160208183030381529060405260405180828051906020019080838360208310610d835780518252601f199092019160209182019101610d64565b600080808080611164611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156111a157600080fd5b505af11580156111b5573d6000803e3d6000fd5b505050506040513d60208110156111cb57600080fd5b505192505b82600160a060020a03166340c9cdeb6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561120e57600080fd5b505af1158015611222573d6000803e3d6000fd5b505050506040513d602081101561123857600080fd5b50518210156112dc5782600160a060020a03166357aeefc5836040518263ffffffff1660e060020a02815260040180828152602001915050602060405180830381600087803b15801561128a57600080fd5b505af115801561129e573d6000803e3d6000fd5b505050506040513d60208110156112b457600080fd5b50519050600160a060020a0380821690871614156112d157600193505b6001909101906111d0565b5091949350505050565b6004600060405160200180807f6f776e657200000000000000000000000000000000000000000000000000000081525060050190506040516020818303038152906040526040518082805190602001908083835b602083106113595780518252601f19909201916020918201910161133a565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a0316331492506113aa91505057600080fd5b6113b2610c55565b156113bc57600080fd5b6113c66001611f8b565b565b60006113d2610d0e565b82106113e0575060006108ab565b436113ea836107da565b11156113f8575060006108ab565b61140182610acb565b1561140e575060006108ab565b611417826114e0565b43101592915050565b606481565b600e90565b60008060008060008060606000806000806000806114478f6107da565b9c506114528f6114e0565b9b5061145d8f610acb565b9a506114688f611c11565b99506114738f6118a3565b985061147e8f611b34565b97506114898f610e5a565b96506114948f6113c8565b95506114a08f8f611a1a565b94506114ab8f610fd0565b93506114b68f610a39565b92506114c18f611062565b91506114cc8f610dc3565b90509295989b9e9194979a9d509295989b50565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f656e64426c6f636b0000000000000000000000000000000000000000000000008152506008019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f696e6465780000000000000000000000000000000000000000000000000000008152506005019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b600061160f83610acb565b1561161957600080fd5b503361162483610ba2565b151561162f57600080fd5b6116398382611a1a565b1561164357600080fd5b60018214806116525750600282145b151561165d57600080fd5b61166883828461204c565b604080518381529051600160a060020a0383169185917f7c2f48a4bf2e759e77b1e77a8bf1034cdf16e9034dad596d3655bb8b315f85eb9181900360200190a3505050565b600060606000806000806000806116c2611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156116ff57600080fd5b505af1158015611713573d6000803e3d6000fd5b505050506040513d602081101561172957600080fd5b5051600160a060020a0316331461173f57600080fd5b88975087151561174e57611897565b611756611a47565b9650600095505b865186101561189757868681518110151561177457fe5b9060200190602002015194504361178a866107da565b10801561179d575061179b85610bc7565b155b1561188c576117ab856113c8565b1561188c576000935060009250600091505b87821015611866576117ea858b8b858181106117d557fe5b90506020020135600160a060020a0316610947565b905060018114156118305761182961181c8b8b8581811061180757fe5b90506020020135600160a060020a031661213d565b859063ffffffff61221516565b935061185b565b600281141561185b5761185861184b8b8b8581811061180757fe5b849063ffffffff61221516565b92505b6001909101906117bd565b6118708585612232565b61187a8584612306565b61188385612397565b61188c85612561565b60019095019461175d565b50505050505050505050565b6000600260008360405160200180806000805160206138a7833981519152815250600b01828152602001807f636f6e7472616374547970650000000000000000000000000000000000000000815250600c019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b6000803361194281611156565b151561194d57600080fd5b88886000821161195c57600080fd5b6000811161196957600080fd5b611971611ea3565b81101561197d57600080fd5b611985611425565b81111561199157600080fd5b600160a060020a03881615156119a657600080fd5b6119af89611e1f565b15156119ba57600080fd5b6119f58b8b89898080601f01602080910402602001604051908101604052809392919081815260200183838082843750612645945050505050565b9350611a018489612742565b611a0b848a61283e565b50919998505050505050505050565b6000600160a060020a0382161515611a3457506000610a33565b611a3e8383610947565b15159392505050565b6060600860006040516020018080600080516020613887833981519152815250600d0190506040516020818303038152906040526040518082805190602001908083835b60208310611aaa5780518252601f199092019160209182019101611a8b565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652858101969096525092830160002080548451818702810187019095528085529394909392508401905082828015611b2a57602002820191906000526020600020905b815481526020019060010190808311611b16575b5050505050905090565b6000600460008360405160200180806000805160206138a7833981519152815250600b01828152602001807f63726561746f72000000000000000000000000000000000000000000000000008152506007019150506040516020818303038152906040526040518082805190602001908083835b60208310611bc75780518252601f199092019160209182019101611ba8565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a031695945050505050565b6000600460008360405160200180806000805160206138a7833981519152815250600b01828152602001807f70726f706f73656456616c756500000000000000000000000000000000000000815250600d0191505060405160208183030381529060405260405180828051906020019080838360208310611bc75780518252601f199092019160209182019101611ba8565b6000600860006040516020018080600080516020613887833981519152815250600d0190506040516020818303038152906040526040518082805190602001908083835b60208310611d065780518252601f199092019160209182019101611ce7565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805490935085925082109050611d4f57fe5b90600052602060002001549050919050565b60006004600060405160200180807f70726f787953746f726167650000000000000000000000000000000000000000815250600c0190506040516020818303038152906040526040518082805190602001908083835b60208310611dd65780518252601f199092019160209182019101611db7565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002054600160a060020a0316949350505050565b6000611e29611d61565b600160a060020a03166333875fdd836040518263ffffffff1660e060020a02815260040180828152602001915050602060405180830381600087803b158015611e7157600080fd5b505af1158015611e85573d6000803e3d6000fd5b505050506040513d6020811015611e9b57600080fd5b505192915050565b600290565b6000600260008360405160200180807f76616c696461746f7241637469766542616c6c6f74730000000000000000000081525060160182600160a060020a0316600160a060020a03166c010000000000000000000000000281526014019150506040516020818303038152906040526040518082805190602001908083836020831061086d5780518252601f19909201916020918201910161084e565b6000806000611f526128cf565b9150811515611f645760649250611f86565b611f7560648363ffffffff6129d016565b9050801515611f82575060015b8092505b505090565b806006600060405160200180807f6973496e697469616c697a656400000000000000000000000000000000000000815250600d0190506040516020818303038152906040526040518082805190602001908083835b60208310611fff5780518252601f199092019160209182019101611fe0565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff19169415159490941790935550505050565b604080516000805160206138a7833981519152602080830191909152602b82018690527f766f746572730000000000000000000000000000000000000000000000000000604b8301526c01000000000000000000000000600160a060020a0386160260518301528251604581840301815260659092019283905281518493600293600093909282918401908083835b602083106120fa5780518252601f1990920191602091820191016120db565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002093909355505050505050565b6000612147611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561218457600080fd5b505af1158015612198573d6000803e3d6000fd5b505050506040513d60208110156121ae57600080fd5b5051604080517fbf135267000000000000000000000000000000000000000000000000000000008152600160a060020a0385811660048301529151919092169163bf1352679160248083019260209291908290030181600087803b158015611e7157600080fd5b60008282018381101561222757600080fd5b8091505b5092915050565b80600260008460405160200180806000805160206138a7833981519152815250600b01828152602001807f61636365707465640000000000000000000000000000000000000000000000008152506008019150506040516020818303038152906040526040518082805190602001908083835b602083106122c45780518252601f1990920191602091820191016122a5565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050565b80600260008460405160200180806000805160206138a7833981519152815250600b01828152602001807f72656a6563746564000000000000000000000000000000000000000000000000815250600801915050604051602081830303815290604052604051808280519060200190808383602083106122c45780518252601f1990920191602091820191016122a5565b61239f611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156123dc57600080fd5b505af11580156123f0573d6000803e3d6000fd5b505050506040513d602081101561240657600080fd5b5051604080517f94409a560000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216916394409a56916004808201926020929091908290030181600087803b15801561246557600080fd5b505af1158015612479573d6000803e3d6000fd5b505050506040513d602081101561248f57600080fd5b5051604080516000805160206138a7833981519152602082810191909152602b82018590527f746f74616c5374616b6500000000000000000000000000000000000000000000604b83015282516035818403018152605590920192839052815160029360009392909182918401908083835b602083106125205780518252601f199092019160209182019101612501565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000209390935550505050565b61256a81610bc7565b151561258257612579816129f3565b61258281612a27565b61258b81612aa3565b156125ec5761259981611062565b6125a282610a39565b11156125d1576125b181612ad4565b156125c7576125c28160025b612b50565b6125cc565b612642565b6125dc565b6125dc8160036125bd565b6125e7816000612be1565b612602565b6125f7816001612be1565b6126028160036125bd565b61260b81612cc1565b612616816001612d16565b60405181907fd470bb0d3dcb39ff5a62757e0a1cdfe60f8200eba22fd0d82383630d457f868690600090a25b50565b6000806000612652610c55565b151561265d57600080fd5b33915061266982612da7565b151561267457600080fd5b61267c610d0e565b905061269761269282600163ffffffff61221516565b612dc1565b6126a18187612e34565b6126ab81866130bd565b6126b6816000612d16565b6126c18160016125bd565b6126cb81836132b5565b6126d58185613346565b6126e6816126e16110f4565b613426565b6126f1816000612be1565b6126fa816134b7565b6127038261356c565b604051600160a060020a0383169082907fe64b3864f6f22f8969f8cb16c039eaf6454ef5e23c09791df010163000a7023590600090a395945050505050565b80600460008460405160200180806000805160206138a7833981519152815250600b01828152602001807f70726f706f73656456616c756500000000000000000000000000000000000000815250600d019150506040516020818303038152906040526040518082805190602001908083835b602083106127d45780518252601f1990920191602091820191016127b5565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0395909516949094179093555050505050565b80600260008460405160200180806000805160206138a7833981519152815250600b01828152602001807f636f6e7472616374547970650000000000000000000000000000000000000000815250600c01915050604051602081830303815290604052604051808280519060200190808383602083106122c45780518252601f1990920191602091820191016122a5565b60006128d9611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561291657600080fd5b505af115801561292a573d6000803e3d6000fd5b505050506040513d602081101561294057600080fd5b5051604080517f40c9cdeb0000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216916340c9cdeb916004808201926020929091908290030181600087803b15801561299f57600080fd5b505af11580156129b3573d6000803e3d6000fd5b505050506040513d60208110156129c957600080fd5b5051905090565b6000808083116129df57600080fd5b82848115156129ea57fe5b04949350505050565b6000806129ff83611b34565b9150612a0a82611ea8565b90506000811115612a2257612a22826001830361358a565b505050565b6001600660008360405160200180807f66696e616c697a6543616c6c6564000000000000000000000000000000000000815250600e0182815260200191505060405160208183030381529060405260405180828051906020019080838360208310611fff5780518252601f199092019160209182019101611fe0565b600080600080612ab285610dc3565b92506127106107d08402049150612ac885610a39565b91909111949350505050565b6000612ade611d61565b600160a060020a031663bb0165b1612af5846118a3565b612afe85611c11565b6040518363ffffffff1660e060020a0281526004018083815260200182600160a060020a0316600160a060020a0316815260200192505050602060405180830381600087803b158015611e7157600080fd5b80600260008460405160200180806000805160206138a7833981519152815250600b01828152602001807f71756f72756d5374617465000000000000000000000000000000000000000000815250600b01915050604051602081830303815290604052604051808280519060200190808383602083106122c45780518252601f1990920191602091820191016122a5565b80600660008460405160200180806000805160206138a7833981519152815250600b01828152602001807f62656c6f775475726e4f75740000000000000000000000000000000000000000815250600c019150506040516020818303038152906040526040518082805190602001908083835b60208310612c735780518252601f199092019160209182019101612c54565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020805460ff1916941515949094179093555050505050565b6000806000612ccf84611572565b92506001612cdb6110f4565b039150612ce782611ca3565b9050612cf38382613626565b612cfd8184613426565b612d08826000613626565b612d106136e1565b50505050565b80600660008460405160200180806000805160206138a7833981519152815250600b01828152602001807f697346696e616c697a6564000000000000000000000000000000000000000000815250600b0191505060405160208183030381529060405260405180828051906020019080838360208310612c735780518252601f199092019160209182019101612c54565b6000612db1611f45565b612dba83611ea8565b1092915050565b806002600060405160200180807f6e65787442616c6c6f7449640000000000000000000000000000000000000000815250600c019050604051602081830303815290604052604051808280519060200190808383602083106125205780518252601f199092019160209182019101612501565b600080600080612e42611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015612e7f57600080fd5b505af1158015612e93573d6000803e3d6000fd5b505050506040513d6020811015612ea957600080fd5b5051604080517fa65249230000000000000000000000000000000000000000000000000000000081529051919550600160a060020a0386169163a6524923916004808201926020929091908290030181600087803b158015612f0a57600080fd5b505af1158015612f1e573d6000803e3d6000fd5b505050506040513d6020811015612f3457600080fd5b5051604080517faf2951810000000000000000000000000000000000000000000000000000000081529051919450600160a060020a0386169163af295181916004808201926020929091908290030181600087803b158015612f9557600080fd5b505af1158015612fa9573d6000803e3d6000fd5b505050506040513d6020811015612fbf57600080fd5b50519150612fe3612fd6868563ffffffff6137a016565b839063ffffffff61221516565b905080600260008860405160200180806000805160206138a7833981519152815250600b01828152602001807f7374617274426c6f636b00000000000000000000000000000000000000000000815250600a019150506040516020818303038152906040526040518082805190602001908083835b602083106130775780518252601f199092019160209182019101613058565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912086528501959095529290920160002093909355505050505050505050565b60008060006130ca611d61565b600160a060020a031663179e740b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561310757600080fd5b505af115801561311b573d6000803e3d6000fd5b505050506040513d602081101561313157600080fd5b5051604080517fa65249230000000000000000000000000000000000000000000000000000000081529051600160a060020a039092169163a6524923916004808201926020929091908290030181600087803b15801561319057600080fd5b505af11580156131a4573d6000803e3d6000fd5b505050506040513d60208110156131ba57600080fd5b505192506131c7856107da565b91506131dc612fd6858563ffffffff6137a016565b905080600260008760405160200180806000805160206138a7833981519152815250600b01828152602001807f656e64426c6f636b0000000000000000000000000000000000000000000000008152506008019150506040516020818303038152906040526040518082805190602001908083835b602083106132705780518252601f199092019160209182019101613251565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285019590955292909201600020939093555050505050505050565b80600460008460405160200180806000805160206138a7833981519152815250600b01828152602001807f63726561746f7200000000000000000000000000000000000000000000000000815250600701915050604051602081830303815290604052604051808280519060200190808383602083106127d45780518252601f1990920191602091820191016127b5565b80600360008460405160200180806000805160206138a7833981519152815250600b01828152602001807f6465736372697074696f6e000000000000000000000000000000000000000000815250600b019150506040516020818303038152906040526040518082805190602001908083835b602083106133d85780518252601f1990920191602091820191016133b9565b51815160001960209485036101000a01908116901991909116179052604080519490920184900390932086528583019690965250929093016000208451612a229591945092019190506137ce565b80600260008460405160200180806000805160206138a7833981519152815250600b01828152602001807f696e646578000000000000000000000000000000000000000000000000000000815250600501915050604051602081830303815290604052604051808280519060200190808383602083106122c45780518252601f1990920191602091820191016122a5565b600860006040516020018080600080516020613887833981519152815250600d0190506040516020818303038152906040526040518082805190602001908083835b602083106135185780518252601f1990920191602091820191016134f9565b51815160209384036101000a60001901801990921691161790526040805192909401829003909120865285810196909652509290920160009081208054600181018255908252939020909201929092555050565b6126428161358a600161357e85611ea8565b9063ffffffff61221516565b80600260008460405160200180807f76616c696461746f7241637469766542616c6c6f74730000000000000000000081525060160182600160a060020a0316600160a060020a03166c01000000000000000000000000028152601401915050604051602081830303815290604052604051808280519060200190808383602083106122c45780518252601f1990920191602091820191016122a5565b80600860006040516020018080600080516020613887833981519152815250600d0190506040516020818303038152906040526040518082805190602001908083835b602083106136885780518252601f199092019160209182019101613669565b51815160209384036101000a600019018019909216911617905260408051929094018290039091208652850195909552929092016000208054909350869250821090506136d157fe5b6000918252602090912001555050565b60006136eb6110f4565b11156113c657600860006040516020018080600080516020613887833981519152815250600d0190506040516020818303038152906040526040518082805190602001908083835b602083106137525780518252601f199092019160209182019101613733565b51815160001960209485036101000a8101918216911992909216179091526040805195909301859003909420875286019690965250929093016000208054935061264292909150830161384c565b6000808315156137b3576000915061222b565b508282028284828115156137c357fe5b041461222757600080fd5b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061380f57805160ff191683800117855561383c565b8280016001018555821561383c579182015b8281111561383c578251825591602001919060010190613821565b5061384892915061386c565b5090565b815481835581811115612a2257600083815260209020612a229181019083015b610d0b91905b808211156138485760008155600101613872560061637469766542616c6c6f747300000000000000000000000000000000000000766f74696e675374617465000000000000000000000000000000000000000000a165627a7a723058208d70072ebed43198b496d8e8560f428fa5f8fefd60a01bc2bd679521aeb93a290029