Overview
POL Balance
0 POL
POL Value
$0.00More Info
Private Name Tags
ContractCreator
Sponsored
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 21936408 | 1015 days ago | IN | 0 POL | 0.03861552 |
Loading...
Loading
Contract Name:
CRVoting
Compiler Version
v0.5.8+commit.23d335f2
Contract Source Code (Solidity)
/** *Submitted for verification at polygonscan.com on 2021-11-29 */ // Brought from https://github.com/aragon/aragonOS/blob/v4.3.0/contracts/lib/math/SafeMath.sol // Adapted to use pragma ^0.5.8 and satisfy our linter rules pragma solidity >=0.4.24 <0.6.0; /** * @title SafeMath * @dev Math operations with safety checks that revert on error */ library SafeMath { string private constant ERROR_ADD_OVERFLOW = "MATH_ADD_OVERFLOW"; string private constant ERROR_SUB_UNDERFLOW = "MATH_SUB_UNDERFLOW"; string private constant ERROR_MUL_OVERFLOW = "MATH_MUL_OVERFLOW"; string private constant ERROR_DIV_ZERO = "MATH_DIV_ZERO"; /** * @dev Multiplies two numbers, 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, ERROR_MUL_OVERFLOW); return c; } /** * @dev Integer division of two numbers truncating the quotient, reverts on division by zero. */ function div(uint256 _a, uint256 _b) internal pure returns (uint256) { require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0 uint256 c = _a / _b; // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { require(_b <= _a, ERROR_SUB_UNDERFLOW); uint256 c = _a - _b; return c; } /** * @dev Adds two numbers, reverts on overflow. */ function add(uint256 _a, uint256 _b) internal pure returns (uint256) { uint256 c = _a + _b; require(c >= _a, ERROR_ADD_OVERFLOW); return c; } /** * @dev Divides two numbers 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, ERROR_DIV_ZERO); return a % b; } } // File: contracts/voting/ICRVotingOwner.sol pragma solidity ^0.5.8; interface ICRVotingOwner { /** * @dev Ensure votes can be committed for a vote instance, revert otherwise * @param _voteId ID of the vote instance to request the weight of a voter for */ function ensureCanCommit(uint256 _voteId) external; /** * @dev Ensure a certain voter can commit votes for a vote instance, revert otherwise * @param _voteId ID of the vote instance to request the weight of a voter for * @param _voter Address of the voter querying the weight of */ function ensureCanCommit(uint256 _voteId, address _voter) external; /** * @dev Ensure a certain voter can reveal votes for vote instance, revert otherwise * @param _voteId ID of the vote instance to request the weight of a voter for * @param _voter Address of the voter querying the weight of * @return Weight of the requested juror for the requested vote instance */ function ensureCanReveal(uint256 _voteId, address _voter) external returns (uint64); } // File: contracts/voting/ICRVoting.sol pragma solidity ^0.5.8; interface ICRVoting { /** * @dev Create a new vote instance * @dev This function can only be called by the CRVoting owner * @param _voteId ID of the new vote instance to be created * @param _possibleOutcomes Number of possible outcomes for the new vote instance to be created */ function create(uint256 _voteId, uint8 _possibleOutcomes) external; /** * @dev Get the winning outcome of a vote instance * @param _voteId ID of the vote instance querying the winning outcome of * @return Winning outcome of the given vote instance or refused in case it's missing */ function getWinningOutcome(uint256 _voteId) external view returns (uint8); /** * @dev Get the tally of an outcome for a certain vote instance * @param _voteId ID of the vote instance querying the tally of * @param _outcome Outcome querying the tally of * @return Tally of the outcome being queried for the given vote instance */ function getOutcomeTally(uint256 _voteId, uint8 _outcome) external view returns (uint256); /** * @dev Tell whether an outcome is valid for a given vote instance or not * @param _voteId ID of the vote instance to check the outcome of * @param _outcome Outcome to check if valid or not * @return True if the given outcome is valid for the requested vote instance, false otherwise */ function isValidOutcome(uint256 _voteId, uint8 _outcome) external view returns (bool); /** * @dev Get the outcome voted by a voter for a certain vote instance * @param _voteId ID of the vote instance querying the outcome of * @param _voter Address of the voter querying the outcome of * @return Outcome of the voter for the given vote instance */ function getVoterOutcome(uint256 _voteId, address _voter) external view returns (uint8); /** * @dev Tell whether a voter voted in favor of a certain outcome in a vote instance or not * @param _voteId ID of the vote instance to query if a voter voted in favor of a certain outcome * @param _outcome Outcome to query if the given voter voted in favor of * @param _voter Address of the voter to query if voted in favor of the given outcome * @return True if the given voter voted in favor of the given outcome, false otherwise */ function hasVotedInFavorOf(uint256 _voteId, uint8 _outcome, address _voter) external view returns (bool); /** * @dev Filter a list of voters based on whether they voted in favor of a certain outcome in a vote instance or not * @param _voteId ID of the vote instance to be checked * @param _outcome Outcome to filter the list of voters of * @param _voters List of addresses of the voters to be filtered * @return List of results to tell whether a voter voted in favor of the given outcome or not */ function getVotersInFavorOf(uint256 _voteId, uint8 _outcome, address[] calldata _voters) external view returns (bool[] memory); } // File: contracts/lib/os/IsContract.sol // Brought from https://github.com/aragon/aragonOS/blob/v4.3.0/contracts/common/IsContract.sol // Adapted to use pragma ^0.5.8 and satisfy our linter rules pragma solidity ^0.5.8; contract IsContract { /* * NOTE: this should NEVER be used for authentication * (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize). * * This is only intended to be used as a sanity check that an address is actually a contract, * RATHER THAN an address not being a contract. */ function isContract(address _target) internal view returns (bool) { if (_target == address(0)) { return false; } uint256 size; assembly { size := extcodesize(_target) } return size > 0; } } // File: contracts/lib/os/SafeMath64.sol // Brought from https://github.com/aragon/aragonOS/blob/v4.3.0/contracts/lib/math/SafeMath64.sol // Adapted to use pragma ^0.5.8 and satisfy our linter rules pragma solidity ^0.5.8; /** * @title SafeMath64 * @dev Math operations for uint64 with safety checks that revert on error */ library SafeMath64 { string private constant ERROR_ADD_OVERFLOW = "MATH64_ADD_OVERFLOW"; string private constant ERROR_SUB_UNDERFLOW = "MATH64_SUB_UNDERFLOW"; string private constant ERROR_MUL_OVERFLOW = "MATH64_MUL_OVERFLOW"; string private constant ERROR_DIV_ZERO = "MATH64_DIV_ZERO"; /** * @dev Multiplies two numbers, reverts on overflow. */ function mul(uint64 _a, uint64 _b) internal pure returns (uint64) { uint256 c = uint256(_a) * uint256(_b); require(c < 0x010000000000000000, ERROR_MUL_OVERFLOW); // 2**64 (less gas this way) return uint64(c); } /** * @dev Integer division of two numbers truncating the quotient, reverts on division by zero. */ function div(uint64 _a, uint64 _b) internal pure returns (uint64) { require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0 uint64 c = _a / _b; // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint64 _a, uint64 _b) internal pure returns (uint64) { require(_b <= _a, ERROR_SUB_UNDERFLOW); uint64 c = _a - _b; return c; } /** * @dev Adds two numbers, reverts on overflow. */ function add(uint64 _a, uint64 _b) internal pure returns (uint64) { uint64 c = _a + _b; require(c >= _a, ERROR_ADD_OVERFLOW); return c; } /** * @dev Divides two numbers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint64 a, uint64 b) internal pure returns (uint64) { require(b != 0, ERROR_DIV_ZERO); return a % b; } } // File: contracts/lib/os/Uint256Helpers.sol // Brought from https://github.com/aragon/aragonOS/blob/v4.3.0/contracts/common/Uint256Helpers.sol // Adapted to use pragma ^0.5.8 and satisfy our linter rules pragma solidity ^0.5.8; library Uint256Helpers { uint256 private constant MAX_UINT8 = uint8(-1); uint256 private constant MAX_UINT64 = uint64(-1); string private constant ERROR_UINT8_NUMBER_TOO_BIG = "UINT8_NUMBER_TOO_BIG"; string private constant ERROR_UINT64_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG"; function toUint8(uint256 a) internal pure returns (uint8) { require(a <= MAX_UINT8, ERROR_UINT8_NUMBER_TOO_BIG); return uint8(a); } function toUint64(uint256 a) internal pure returns (uint64) { require(a <= MAX_UINT64, ERROR_UINT64_NUMBER_TOO_BIG); return uint64(a); } } // File: contracts/lib/os/TimeHelpers.sol // Brought from https://github.com/aragon/aragonOS/blob/v4.3.0/contracts/common/TimeHelpers.sol // Adapted to use pragma ^0.5.8 and satisfy our linter rules pragma solidity ^0.5.8; contract TimeHelpers { using Uint256Helpers for uint256; /** * @dev Returns the current block number. * Using a function rather than `block.number` allows us to easily mock the block number in * tests. */ function getBlockNumber() internal view returns (uint256) { return block.number; } /** * @dev Returns the current block number, converted to uint64. * Using a function rather than `block.number` allows us to easily mock the block number in * tests. */ function getBlockNumber64() internal view returns (uint64) { return getBlockNumber().toUint64(); } /** * @dev Returns the current timestamp. * Using a function rather than `block.timestamp` allows us to easily mock it in * tests. */ function getTimestamp() internal view returns (uint256) { return block.timestamp; // solium-disable-line security/no-block-members } /** * @dev Returns the current timestamp, converted to uint64. * Using a function rather than `block.timestamp` allows us to easily mock it in * tests. */ function getTimestamp64() internal view returns (uint64) { return getTimestamp().toUint64(); } } // File: contracts/lib/os/ERC20.sol // Brought from https://github.com/aragon/aragonOS/blob/v4.3.0/contracts/lib/token/ERC20.sol // Adapted to use pragma ^0.5.8 and satisfy our linter rules pragma solidity ^0.5.8; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 { function totalSupply() public view returns (uint256); function balanceOf(address _who) public view returns (uint256); function allowance(address _owner, address _spender) public view returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); function transferFrom(address _from, address _to, uint256 _value) public returns (bool); event Transfer( address indexed from, address indexed to, uint256 value ); event Approval( address indexed owner, address indexed spender, uint256 value ); } // File: contracts/court/clock/IClock.sol pragma solidity ^0.5.8; interface IClock { /** * @dev Ensure that the current term of the clock is up-to-date * @return Identification number of the current term */ function ensureCurrentTerm() external returns (uint64); /** * @dev Transition up to a certain number of terms to leave the clock up-to-date * @param _maxRequestedTransitions Max number of term transitions allowed by the sender * @return Identification number of the term ID after executing the heartbeat transitions */ function heartbeat(uint64 _maxRequestedTransitions) external returns (uint64); /** * @dev Ensure that a certain term has its randomness set * @return Randomness of the current term */ function ensureCurrentTermRandomness() external returns (bytes32); /** * @dev Tell the last ensured term identification number * @return Identification number of the last ensured term */ function getLastEnsuredTermId() external view returns (uint64); /** * @dev Tell the current term identification number. Note that there may be pending term transitions. * @return Identification number of the current term */ function getCurrentTermId() external view returns (uint64); /** * @dev Tell the number of terms the clock should transition to be up-to-date * @return Number of terms the clock should transition to be up-to-date */ function getNeededTermTransitions() external view returns (uint64); /** * @dev Tell the information related to a term based on its ID * @param _termId ID of the term being queried * @return startTime Term start time * @return randomnessBN Block number used for randomness in the requested term * @return randomness Randomness computed for the requested term * @return celesteTokenTotalSupply Total supply of the Celeste token */ function getTerm(uint64 _termId) external view returns (uint64 startTime, uint64 randomnessBN, bytes32 randomness, uint256 celesteTokenTotalSupply); /** * @dev Tell the randomness of a term even if it wasn't computed yet * @param _termId Identification number of the term being queried * @return Randomness of the requested term */ function getTermRandomness(uint64 _termId) external view returns (bytes32); /** * @dev Tell the total supply of the celeste token at a specific term * @param _termId Identification number of the term being queried * @return Total supply of celeste token */ function getTermTokenTotalSupply(uint64 _termId) external view returns (uint256); } // File: contracts/court/clock/CourtClock.sol pragma solidity ^0.5.8; contract CourtClock is IClock, TimeHelpers { using SafeMath64 for uint64; string private constant ERROR_TERM_DOES_NOT_EXIST = "CLK_TERM_DOES_NOT_EXIST"; string private constant ERROR_TERM_DURATION_TOO_LONG = "CLK_TERM_DURATION_TOO_LONG"; string private constant ERROR_TERM_RANDOMNESS_NOT_YET = "CLK_TERM_RANDOMNESS_NOT_YET"; string private constant ERROR_TERM_RANDOMNESS_UNAVAILABLE = "CLK_TERM_RANDOMNESS_UNAVAILABLE"; string private constant ERROR_BAD_FIRST_TERM_START_TIME = "CLK_BAD_FIRST_TERM_START_TIME"; string private constant ERROR_TOO_MANY_TRANSITIONS = "CLK_TOO_MANY_TRANSITIONS"; string private constant ERROR_INVALID_TRANSITION_TERMS = "CLK_INVALID_TRANSITION_TERMS"; string private constant ERROR_CANNOT_DELAY_STARTED_COURT = "CLK_CANNOT_DELAY_STARTED_COURT"; string private constant ERROR_CANNOT_DELAY_PAST_START_TIME = "CLK_CANNOT_DELAY_PAST_START_TIME"; // Maximum number of term transitions a callee may have to assume in order to call certain functions that require the Court being up-to-date uint64 internal constant MAX_AUTO_TERM_TRANSITIONS_ALLOWED = 1; // Max duration in seconds that a term can last uint64 internal constant MAX_TERM_DURATION = 365 days; // Max time until first term starts since contract is deployed uint64 internal constant MAX_FIRST_TERM_DELAY_PERIOD = 2 * MAX_TERM_DURATION; struct Term { uint64 startTime; // Timestamp when the term started uint64 randomnessBN; // Block number for entropy bytes32 randomness; // Entropy from randomnessBN block hash uint256 celesteTokenTotalSupply; } // Duration in seconds for each term of the Court uint64 private termDuration; // Last ensured term id uint64 private termId; // List of Court terms indexed by id mapping (uint64 => Term) private terms; event Heartbeat(uint64 previousTermId, uint64 currentTermId); event StartTimeDelayed(uint64 previousStartTime, uint64 currentStartTime); /** * @dev Ensure a certain term has already been processed * @param _termId Identification number of the term to be checked */ modifier termExists(uint64 _termId) { require(_termId <= termId, ERROR_TERM_DOES_NOT_EXIST); _; } /** * @dev Constructor function * @param _termParams Array containing: * 0. _termDuration Duration in seconds per term * 1. _firstTermStartTime Timestamp in seconds when the court will open (to give time for juror on-boarding) */ constructor(uint64[2] memory _termParams, ERC20 _celesteToken) public { uint64 _termDuration = _termParams[0]; uint64 _firstTermStartTime = _termParams[1]; require(_termDuration < MAX_TERM_DURATION, ERROR_TERM_DURATION_TOO_LONG); require(_firstTermStartTime >= getTimestamp64() + _termDuration, ERROR_BAD_FIRST_TERM_START_TIME); require(_firstTermStartTime <= getTimestamp64() + MAX_FIRST_TERM_DELAY_PERIOD, ERROR_BAD_FIRST_TERM_START_TIME); termDuration = _termDuration; // No need for SafeMath: we already checked values above terms[0].startTime = _firstTermStartTime - _termDuration; terms[0].celesteTokenTotalSupply = _celesteToken.totalSupply(); } /** * @notice Ensure that the current term of the Court is up-to-date. If the Court is outdated by more than `MAX_AUTO_TERM_TRANSITIONS_ALLOWED` * terms, the heartbeat function must be called manually instead. * @return Identification number of the current term */ function ensureCurrentTerm() external returns (uint64) { return _ensureCurrentTerm(); } /** * @notice Transition up to `_maxRequestedTransitions` terms * @param _maxRequestedTransitions Max number of term transitions allowed by the sender * @return Identification number of the term ID after executing the heartbeat transitions */ function heartbeat(uint64 _maxRequestedTransitions) external returns (uint64) { return _heartbeat(_maxRequestedTransitions); } /** * @notice Ensure that a certain term has its randomness set. As we allow to draft disputes requested for previous terms, if there * were mined more than 256 blocks for the current term, the blockhash of its randomness BN is no longer available, given * round will be able to be drafted in the following term. * @return Randomness of the current term */ function ensureCurrentTermRandomness() external returns (bytes32) { // If the randomness for the given term was already computed, return uint64 currentTermId = termId; Term storage term = terms[currentTermId]; bytes32 termRandomness = term.randomness; if (termRandomness != bytes32(0)) { return termRandomness; } // Compute term randomness bytes32 newRandomness = _computeTermRandomness(currentTermId); require(newRandomness != bytes32(0), ERROR_TERM_RANDOMNESS_UNAVAILABLE); term.randomness = newRandomness; return newRandomness; } /** * @dev Tell the term duration of the Court * @return Duration in seconds of the Court term */ function getTermDuration() external view returns (uint64) { return termDuration; } /** * @dev Tell the last ensured term identification number * @return Identification number of the last ensured term */ function getLastEnsuredTermId() external view returns (uint64) { return _lastEnsuredTermId(); } /** * @dev Tell the current term identification number. Note that there may be pending term transitions. * @return Identification number of the current term */ function getCurrentTermId() external view returns (uint64) { return _currentTermId(); } /** * @dev Tell the number of terms the Court should transition to be up-to-date * @return Number of terms the Court should transition to be up-to-date */ function getNeededTermTransitions() external view returns (uint64) { return _neededTermTransitions(); } /** * @dev Tell the information related to a term based on its ID. Note that if the term has not been reached, the * information returned won't be computed yet. This function allows querying future terms that were not computed yet. * @param _termId ID of the term being queried * @return startTime Term start time * @return randomnessBN Block number used for randomness in the requested term * @return randomness Randomness computed for the requested term * @return celesteTokenTotalSupply Total supply of the Celeste token */ function getTerm(uint64 _termId) external view returns (uint64 startTime, uint64 randomnessBN, bytes32 randomness, uint256 celesteTokenTotalSupply) { Term storage term = terms[_termId]; return (term.startTime, term.randomnessBN, term.randomness, term.celesteTokenTotalSupply); } /** * @dev Tell the randomness of a term even if it wasn't computed yet * @param _termId Identification number of the term being queried * @return Randomness of the requested term */ function getTermRandomness(uint64 _termId) external view termExists(_termId) returns (bytes32) { return _computeTermRandomness(_termId); } /** * @dev Tell the total supply of the celeste token at a specific term * @param _termId Identification number of the term being queried * @return Total supply of celeste token */ function getTermTokenTotalSupply(uint64 _termId) external view termExists(_termId) returns (uint256) { return terms[_termId].celesteTokenTotalSupply; } /** * @dev Internal function to ensure that the current term of the Court is up-to-date. If the Court is outdated by more than * `MAX_AUTO_TERM_TRANSITIONS_ALLOWED` terms, the heartbeat function must be called manually. * @return Identification number of the resultant term ID after executing the corresponding transitions */ function _ensureCurrentTerm() internal returns (uint64) { // Check the required number of transitions does not exceeds the max allowed number to be processed automatically uint64 requiredTransitions = _neededTermTransitions(); require(requiredTransitions <= MAX_AUTO_TERM_TRANSITIONS_ALLOWED, ERROR_TOO_MANY_TRANSITIONS); // If there are no transitions pending, return the last ensured term id if (uint256(requiredTransitions) == 0) { return termId; } // Process transition if there is at least one pending return _heartbeat(requiredTransitions); } /** * @dev Internal function to transition the Court terms up to a requested number of terms * @param _maxRequestedTransitions Max number of term transitions allowed by the sender * @return Identification number of the resultant term ID after executing the requested transitions */ function _heartbeat(uint64 _maxRequestedTransitions) internal returns (uint64) { // Transition the minimum number of terms between the amount requested and the amount actually needed uint64 neededTransitions = _neededTermTransitions(); uint256 transitions = uint256(_maxRequestedTransitions < neededTransitions ? _maxRequestedTransitions : neededTransitions); require(transitions > 0, ERROR_INVALID_TRANSITION_TERMS); uint64 blockNumber = getBlockNumber64(); uint64 previousTermId = termId; uint64 currentTermId = previousTermId; for (uint256 transition = 1; transition <= transitions; transition++) { // Term IDs are incremented by one based on the number of time periods since the Court started. Since time is represented in uint64, // even if we chose the minimum duration possible for a term (1 second), we can ensure terms will never reach 2^64 since time is // already assumed to fit in uint64. Term storage previousTerm = terms[currentTermId++]; Term storage currentTerm = terms[currentTermId]; (ERC20 feeToken,,,,,, uint256[4] memory jurorsParams) = _getConfig(currentTermId); _onTermTransitioned(currentTermId); // Set the start time of the new term. Note that we are using a constant term duration value to guarantee // equally long terms, regardless of heartbeats. currentTerm.startTime = previousTerm.startTime.add(termDuration); // In order to draft a random number of jurors in a term, we use a randomness factor for each term based on a // block number that is set once the term has started. Note that this information could not be known beforehand. currentTerm.randomnessBN = blockNumber + 1; // We check if the feeTokenTotalSupply is set, which means this networks feeToken doesn't have an accurate // totalSupply so we will use the hardcoded value currentTerm.celesteTokenTotalSupply = jurorsParams[3] > 0 ? jurorsParams[3] : feeToken.totalSupply(); } termId = currentTermId; emit Heartbeat(previousTermId, currentTermId); return currentTermId; } /** * @dev Internal function to delay the first term start time only if it wasn't reached yet * @param _newFirstTermStartTime New timestamp in seconds when the court will open */ function _delayStartTime(uint64 _newFirstTermStartTime) internal { require(_currentTermId() == 0, ERROR_CANNOT_DELAY_STARTED_COURT); Term storage term = terms[0]; uint64 currentFirstTermStartTime = term.startTime.add(termDuration); require(_newFirstTermStartTime > currentFirstTermStartTime, ERROR_CANNOT_DELAY_PAST_START_TIME); // No need for SafeMath: we already checked above that `_newFirstTermStartTime` > `currentFirstTermStartTime` >= `termDuration` term.startTime = _newFirstTermStartTime - termDuration; emit StartTimeDelayed(currentFirstTermStartTime, _newFirstTermStartTime); } /** * @dev Internal function to notify when a term has been transitioned. This function must be overridden to provide custom behavior. * @param _termId Identification number of the new current term that has been transitioned */ function _onTermTransitioned(uint64 _termId) internal; /** * @dev Internal function to tell the last ensured term identification number * @return Identification number of the last ensured term */ function _lastEnsuredTermId() internal view returns (uint64) { return termId; } /** * @dev Internal function to tell the current term identification number. Note that there may be pending term transitions. * @return Identification number of the current term */ function _currentTermId() internal view returns (uint64) { return termId.add(_neededTermTransitions()); } /** * @dev Internal function to tell the number of terms the Court should transition to be up-to-date * @return Number of terms the Court should transition to be up-to-date */ function _neededTermTransitions() internal view returns (uint64) { // Note that the Court is always initialized providing a start time for the first-term in the future. If that's the case, // no term transitions are required. uint64 currentTermStartTime = terms[termId].startTime; if (getTimestamp64() < currentTermStartTime) { return uint64(0); } // No need for SafeMath: we already know that the start time of the current term is in the past return (getTimestamp64() - currentTermStartTime) / termDuration; } /** * @dev Internal function to compute the randomness that will be used to draft jurors for the given term. This * function assumes the given term exists. To determine the randomness factor for a term we use the hash of a * block number that is set once the term has started to ensure it cannot be known beforehand. Note that the * hash function being used only works for the 256 most recent block numbers. * @param _termId Identification number of the term being queried * @return Randomness computed for the given term */ function _computeTermRandomness(uint64 _termId) internal view returns (bytes32) { Term storage term = terms[_termId]; require(getBlockNumber64() > term.randomnessBN, ERROR_TERM_RANDOMNESS_NOT_YET); return blockhash(term.randomnessBN); } /** * @dev Tell the full Court configuration parameters at a certain term * @param _termId Identification number of the term querying the Court config of * @return token Address of the token used to pay for fees * @return fees Array containing: * 0. jurorFee Amount of fee tokens that is paid per juror per dispute * 1. draftFee Amount of fee tokens per juror to cover the drafting cost * 2. settleFee Amount of fee tokens per juror to cover round settlement cost * @return maxRulingOptions Max number of selectable outcomes for each dispute * @return roundParams Array containing durations of phases of a dispute and other params for rounds: * 0. evidenceTerms Max submitting evidence period duration in terms * 1. commitTerms Commit period duration in terms * 2. revealTerms Reveal period duration in terms * 3. appealTerms Appeal period duration in terms * 4. appealConfirmationTerms Appeal confirmation period duration in terms * 5. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 6. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 7. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 8. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @return pcts Array containing: * 0. penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) * 1. finalRoundReduction Permyriad of fee reduction for the last appeal round (‱ - 1/10,000) * @return appealCollateralParams Array containing params for appeal collateral: * 0. appealCollateralFactor Multiple of dispute fees required to appeal a preliminary ruling * 1. appealConfirmCollateralFactor Multiple of dispute fees required to confirm appeal * @return jurorsParams Array containing params for juror registry: * 0. minActiveBalance Minimum amount of juror tokens that can be activated * 1. minMaxPctTotalSupply The min max percent of the total supply a juror can activate, applied for total supply active stake * 2. maxMaxPctTotalSupply The max max percent of the total supply a juror can activate, applied for 0 active stake * 3. feeTokenTotalSupply Set for networks that don't have access to the fee token's total supply, set to 0 for networks that do */ function _getConfig(uint64 _termId) internal view returns ( ERC20 feeToken, uint256[3] memory fees, uint8 maxRulingOptions, uint64[9] memory roundParams, uint16[2] memory pcts, uint256[2] memory appealCollateralParams, uint256[4] memory jurorsParams ); } // File: contracts/court/config/IConfig.sol pragma solidity ^0.5.8; interface IConfig { /** * @dev Tell the full Court configuration parameters at a certain term * @param _termId Identification number of the term querying the Court config of * @return token Address of the token used to pay for fees * @return fees Array containing: * 0. jurorFee Amount of fee tokens that is paid per juror per dispute * 1. draftFee Amount of fee tokens per juror to cover the drafting cost * 2. settleFee Amount of fee tokens per juror to cover round settlement cost * @return maxRulingOptions Max number of selectable outcomes for each dispute * @return roundParams Array containing durations of phases of a dispute and other params for rounds: * 0. evidenceTerms Max submitting evidence period duration in terms * 1. commitTerms Commit period duration in terms * 2. revealTerms Reveal period duration in terms * 3. appealTerms Appeal period duration in terms * 4. appealConfirmationTerms Appeal confirmation period duration in terms * 5. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 6. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 7. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 8. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @return pcts Array containing: * 0. penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) * 1. finalRoundReduction Permyriad of fee reduction for the last appeal round (‱ - 1/10,000) * @return appealCollateralParams Array containing params for appeal collateral: * 0. appealCollateralFactor Multiple of dispute fees required to appeal a preliminary ruling * 1. appealConfirmCollateralFactor Multiple of dispute fees required to confirm appeal * @return jurorsParams Array containing params for juror registry: * 0. minActiveBalance Minimum amount of juror tokens that can be activated * 1. minMaxPctTotalSupply The min max percent of the total supply a juror can activate, applied for total supply active stake * 2. maxMaxPctTotalSupply The max max percent of the total supply a juror can activate, applied for 0 active stake * 3. feeTokenTotalSupply Set for networks that don't have access to the fee token's total supply, set to 0 for networks that do */ function getConfig(uint64 _termId) external view returns ( ERC20 feeToken, uint256[3] memory fees, uint8 maxRulingOptions, uint64[9] memory roundParams, uint16[2] memory pcts, uint256[2] memory appealCollateralParams, uint256[4] memory jurorsParams ); /** * @dev Tell the draft config at a certain term * @param _termId Identification number of the term querying the draft config of * @return feeToken Address of the token used to pay for fees * @return draftFee Amount of fee tokens per juror to cover the drafting cost * @return penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) */ function getDraftConfig(uint64 _termId) external view returns (ERC20 feeToken, uint256 draftFee, uint16 penaltyPct); /** * @dev Tell the min active balance config at a certain term * @param _termId Term querying the min active balance config of * @return Minimum amount of tokens jurors have to activate to participate in the Court */ function getMinActiveBalance(uint64 _termId) external view returns (uint256); /** * @dev Tell whether a certain holder accepts automatic withdrawals of tokens or not * @return True if the given holder accepts automatic withdrawals of their tokens, false otherwise */ function areWithdrawalsAllowedFor(address _holder) external view returns (bool); } // File: contracts/court/config/CourtConfigData.sol pragma solidity ^0.5.8; contract CourtConfigData { struct Config { FeesConfig fees; // Full fees-related config DisputesConfig disputes; // Full disputes-related config JurorsConfig jurors; // Full juror-related config } struct FeesConfig { ERC20 token; // ERC20 token to be used for the fees of the Court uint16 finalRoundReduction; // Permyriad of fees reduction applied for final appeal round (‱ - 1/10,000) uint256 jurorFee; // Amount of tokens paid to draft a juror to adjudicate a dispute uint256 draftFee; // Amount of tokens paid per round to cover the costs of drafting jurors uint256 settleFee; // Amount of tokens paid per round to cover the costs of slashing jurors } struct DisputesConfig { uint8 maxRulingOptions; // Max number of ruling options selectable by jurors for a dispute uint64 evidenceTerms; // Max submitting evidence period duration in terms uint64 commitTerms; // Committing period duration in terms uint64 revealTerms; // Revealing period duration in terms uint64 appealTerms; // Appealing period duration in terms uint64 appealConfirmTerms; // Confirmation appeal period duration in terms uint16 penaltyPct; // Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) uint64 firstRoundJurorsNumber; // Number of jurors drafted on first round uint64 appealStepFactor; // Factor in which the jurors number is increased on each appeal uint64 finalRoundLockTerms; // Period a coherent juror in the final round will remain locked uint256 maxRegularAppealRounds; // Before the final appeal uint256 appealCollateralFactor; // Permyriad multiple of dispute fees required to appeal a preliminary ruling (‱ - 1/10,000) uint256 appealConfirmCollateralFactor; // Permyriad multiple of dispute fees required to confirm appeal (‱ - 1/10,000) } struct JurorsConfig { uint256 minActiveBalance; // Minimum amount of tokens jurors have to activate to participate in the Court uint256 minMaxPctTotalSupply; // Minimum max percent of the total supply a juror can activate, applied for total supply active stake uint256 maxMaxPctTotalSupply; // Maximum max percent of the total supply a juror can activate, applied for 0 active stake uint256 feeTokenTotalSupply; // Set for networks that don't have access to the fee token's total supply, set to 0 for networks that do } struct DraftConfig { ERC20 feeToken; // ERC20 token to be used for the fees of the Court uint16 penaltyPct; // Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) uint256 draftFee; // Amount of tokens paid per round to cover the costs of drafting jurors } } // File: contracts/lib/PctHelpers.sol pragma solidity ^0.5.8; library PctHelpers { using SafeMath for uint256; uint256 internal constant PCT_BASE = 10000; // ‱ (1 / 10,000) uint256 internal constant PCT_BASE_HIGH_PRECISION = 1e18; // 100% function isValid(uint16 _pct) internal pure returns (bool) { return _pct <= PCT_BASE; } function isValidHighPrecision(uint256 _pct) internal pure returns (bool) { return _pct <= PCT_BASE_HIGH_PRECISION; } function pct(uint256 self, uint16 _pct) internal pure returns (uint256) { return self.mul(uint256(_pct)) / PCT_BASE; } function pct256(uint256 self, uint256 _pct) internal pure returns (uint256) { return self.mul(_pct) / PCT_BASE; } function pctHighPrecision(uint256 self, uint256 _pct) internal pure returns (uint256) { return self.mul(_pct) / PCT_BASE_HIGH_PRECISION; } function pctIncrease(uint256 self, uint16 _pct) internal pure returns (uint256) { // No need for SafeMath: for addition note that `PCT_BASE` is lower than (2^256 - 2^16) return self.mul(PCT_BASE + uint256(_pct)) / PCT_BASE; } } // File: contracts/court/config/CourtConfig.sol pragma solidity ^0.5.8; contract CourtConfig is IConfig, CourtConfigData { using SafeMath64 for uint64; using PctHelpers for uint256; string private constant ERROR_TOO_OLD_TERM = "CONF_TOO_OLD_TERM"; string private constant ERROR_RULING_OPTIONS_LESS_THAN_MIN = "CONF_RULING_OPTIONS_LESS_THAN_MIN"; string private constant ERROR_RULING_OPTIONS_MORE_THAN_MAX = "CONF_RULING_OPTIONS_MORE_THAN_MAX"; string private constant ERROR_INVALID_PENALTY_PCT = "CONF_INVALID_PENALTY_PCT"; string private constant ERROR_INVALID_FINAL_ROUND_REDUCTION_PCT = "CONF_INVALID_FINAL_ROUND_RED_PCT"; string private constant ERROR_INVALID_MAX_APPEAL_ROUNDS = "CONF_INVALID_MAX_APPEAL_ROUNDS"; string private constant ERROR_LARGE_ROUND_PHASE_DURATION = "CONF_LARGE_ROUND_PHASE_DURATION"; string private constant ERROR_BAD_INITIAL_JURORS_NUMBER = "CONF_BAD_INITIAL_JURORS_NUMBER"; string private constant ERROR_BAD_APPEAL_STEP_FACTOR = "CONF_BAD_APPEAL_STEP_FACTOR"; string private constant ERROR_ZERO_COLLATERAL_FACTOR = "CONF_ZERO_COLLATERAL_FACTOR"; string private constant ERROR_ZERO_MIN_ACTIVE_BALANCE = "CONF_ZERO_MIN_ACTIVE_BALANCE"; string private constant ERROR_MIN_MAX_TOTAL_SUPPLY_ZERO = "CONF_MIN_MAX_TOTAL_SUPPLY_ZERO"; string private constant ERROR_INVALID_MAX_MAX_TOTAL_SUPPLY_PCT = "CONF_INVALID_MAX_MAX_TOTAL_SUPPLY_PCT"; string private constant ERROR_MIN_MORE_THAN_MAX_ACTIVE_PCT = "CONF_MIN_MORE_THAN_MAX_ACTIVE_PCT"; // Max number of terms that each of the different adjudication states can last (if lasted 1h, this would be a year) uint64 internal constant MAX_ADJ_STATE_DURATION = 8670; // Cap the max number of regular appeal rounds uint256 internal constant MAX_REGULAR_APPEAL_ROUNDS_LIMIT = 10; // Future term ID in which a config change has been scheduled uint64 private configChangeTermId; // List of all the configs used in the Court Config[] private configs; // List of configs indexed by id mapping (uint64 => uint256) private configIdByTerm; // Holders opt-in config for automatic withdrawals mapping (address => bool) private withdrawalsAllowed; event NewConfig(uint64 fromTermId, uint64 courtConfigId); event AutomaticWithdrawalsAllowedChanged(address indexed holder, bool allowed); /** * @dev Constructor function * @param _feeToken Address of the token contract that is used to pay for fees * @param _fees Array containing: * 0. jurorFee Amount of fee tokens that is paid per juror per dispute * 1. draftFee Amount of fee tokens per juror to cover the drafting cost * 2. settleFee Amount of fee tokens per juror to cover round settlement cost * @param _maxRulingOptions Max number of selectable outcomes for each dispute * @param _roundParams Array containing durations of phases of a dispute and other params for rounds: * 0. evidenceTerms Max submitting evidence period duration in terms * 1. commitTerms Commit period duration in terms * 2. revealTerms Reveal period duration in terms * 3. appealTerms Appeal period duration in terms * 4. appealConfirmationTerms Appeal confirmation period duration in terms * 5. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 6. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 7. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 8. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @param _pcts Array containing: * 0. penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) * 1. finalRoundReduction Permyriad of fee reduction for the last appeal round (‱ - 1/10,000) * @param _appealCollateralParams Array containing params for appeal collateral: * 0. appealCollateralFactor Multiple of dispute fees required to appeal a preliminary ruling * 1. appealConfirmCollateralFactor Multiple of dispute fees required to confirm appeal * @param _jurorsParams Array containing params for juror registry: * 0. minActiveBalance Minimum amount of juror tokens that can be activated * 1. minMaxPctTotalSupply The min max percent of the total supply a juror can activate, applied for total supply active stake * 2. maxMaxPctTotalSupply The max max percent of the total supply a juror can activate, applied for 0 active stake * 3. feeTokenTotalSupply Set for networks that don't have access to the fee token's total supply, set to 0 for networks that do */ constructor( ERC20 _feeToken, uint256[3] memory _fees, uint8 _maxRulingOptions, uint64[9] memory _roundParams, uint16[2] memory _pcts, uint256[2] memory _appealCollateralParams, uint256[4] memory _jurorsParams ) public { // Leave config at index 0 empty for non-scheduled config changes configs.length = 1; _setConfig( 0, 0, _feeToken, _fees, _maxRulingOptions, _roundParams, _pcts, _appealCollateralParams, _jurorsParams ); } /** * @notice Set the automatic withdrawals config for the sender to `_allowed` * @param _allowed Whether or not the automatic withdrawals are allowed by the sender */ function setAutomaticWithdrawals(bool _allowed) external { withdrawalsAllowed[msg.sender] = _allowed; emit AutomaticWithdrawalsAllowedChanged(msg.sender, _allowed); } /** * @dev Tell the full Court configuration parameters at a certain term * @param _termId Identification number of the term querying the Court config of * @return token Address of the token used to pay for fees * @return fees Array containing: * 0. jurorFee Amount of fee tokens that is paid per juror per dispute * 1. draftFee Amount of fee tokens per juror to cover the drafting cost * 2. settleFee Amount of fee tokens per juror to cover round settlement cost * @return maxRulingOptions Max number of selectable outcomes for each dispute * @return roundParams Array containing durations of phases of a dispute and other params for rounds: * 0. evidenceTerms Max submitting evidence period duration in terms * 1. commitTerms Commit period duration in terms * 2. revealTerms Reveal period duration in terms * 3. appealTerms Appeal period duration in terms * 4. appealConfirmationTerms Appeal confirmation period duration in terms * 5. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 6. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 7. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 8. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @return pcts Array containing: * 0. penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) * 1. finalRoundReduction Permyriad of fee reduction for the last appeal round (‱ - 1/10,000) * @return appealCollateralParams Array containing params for appeal collateral: * 0. appealCollateralFactor Multiple of dispute fees required to appeal a preliminary ruling * 1. appealConfirmCollateralFactor Multiple of dispute fees required to confirm appeal * @return jurorsParams Array containing params for juror registry: * 0. minActiveBalance Minimum amount of juror tokens that can be activated * 1. minMaxPctTotalSupply The min max percent of the total supply a juror can activate, applied for total supply active stake * 2. maxMaxPctTotalSupply The max max percent of the total supply a juror can activate, applied for 0 active stake * 3. feeTokenTotalSupply Set for networks that don't have access to the fee token's total supply, set to 0 for networks that do */ function getConfig(uint64 _termId) external view returns ( ERC20 feeToken, uint256[3] memory fees, uint8 maxRulingOptions, uint64[9] memory roundParams, uint16[2] memory pcts, uint256[2] memory appealCollateralParams, uint256[4] memory jurorsParams ); /** * @dev Tell the draft config at a certain term * @param _termId Identification number of the term querying the draft config of * @return feeToken Address of the token used to pay for fees * @return draftFee Amount of fee tokens per juror to cover the drafting cost * @return penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) */ function getDraftConfig(uint64 _termId) external view returns (ERC20 feeToken, uint256 draftFee, uint16 penaltyPct); /** * @dev Tell the min active balance config at a certain term * @param _termId Term querying the min active balance config of * @return Minimum amount of tokens jurors have to activate to participate in the Court */ function getMinActiveBalance(uint64 _termId) external view returns (uint256); /** * @dev Tell whether a certain holder accepts automatic withdrawals of tokens or not * @param _holder Address of the token holder querying if withdrawals are allowed for * @return True if the given holder accepts automatic withdrawals of their tokens, false otherwise */ function areWithdrawalsAllowedFor(address _holder) external view returns (bool) { return withdrawalsAllowed[_holder]; } /** * @dev Tell the term identification number of the next scheduled config change * @return Term identification number of the next scheduled config change */ function getConfigChangeTermId() external view returns (uint64) { return configChangeTermId; } /** * @dev Internal to make sure to set a config for the new term, it will copy the previous term config if none * @param _termId Identification number of the new current term that has been transitioned */ function _ensureTermConfig(uint64 _termId) internal { // If the term being transitioned had no config change scheduled, keep the previous one uint256 currentConfigId = configIdByTerm[_termId]; if (currentConfigId == 0) { uint256 previousConfigId = configIdByTerm[_termId.sub(1)]; configIdByTerm[_termId] = previousConfigId; } } /** * @dev Assumes that sender it's allowed (either it's from governor or it's on init) * @param _termId Identification number of the current Court term * @param _fromTermId Identification number of the term in which the config will be effective at * @param _feeToken Address of the token contract that is used to pay for fees. * @param _fees Array containing: * 0. jurorFee Amount of fee tokens that is paid per juror per dispute * 1. draftFee Amount of fee tokens per juror to cover the drafting cost * 2. settleFee Amount of fee tokens per juror to cover round settlement cost * @param _maxRulingOptions Max number of selectable outcomes for each dispute * @param _roundParams Array containing durations of phases of a dispute and other params for rounds: * 0. evidenceTerms Max submitting evidence period duration in terms * 1. commitTerms Commit period duration in terms * 2. revealTerms Reveal period duration in terms * 3. appealTerms Appeal period duration in terms * 4. appealConfirmationTerms Appeal confirmation period duration in terms * 5. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 6. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 7. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 8. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @param _pcts Array containing: * 0. penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) * 1. finalRoundReduction Permyriad of fee reduction for the last appeal round (‱ - 1/10,000) * @param _appealCollateralParams Array containing params for appeal collateral: * 0. appealCollateralFactor Multiple of dispute fees required to appeal a preliminary ruling * 1. appealConfirmCollateralFactor Multiple of dispute fees required to confirm appeal * @param _jurorsParams Array containing params for juror registry: * 0. minActiveBalance Minimum amount of juror tokens that can be activated * 1. minMaxPctTotalSupply The min max percent of the total supply a juror can activate, applied for total supply active stake * 2. maxMaxPctTotalSupply The max max percent of the total supply a juror can activate, applied for 0 active stake * 3. feeTokenTotalSupply Set for networks that don't have access to the fee token's total supply, set to 0 for networks that do */ function _setConfig( uint64 _termId, uint64 _fromTermId, ERC20 _feeToken, uint256[3] memory _fees, uint8 _maxRulingOptions, uint64[9] memory _roundParams, uint16[2] memory _pcts, uint256[2] memory _appealCollateralParams, uint256[4] memory _jurorsParams ) internal { // If the current term is not zero, changes must be scheduled at least after the current period. // No need to ensure delays for on-going disputes since these already use their creation term for that. require(_termId == 0 || _fromTermId > _termId, ERROR_TOO_OLD_TERM); require(_maxRulingOptions >= 2, ERROR_RULING_OPTIONS_LESS_THAN_MIN); // Ruling options 0, 1 and 2 are reserved for special cases. require(_maxRulingOptions <= uint8(-1) - 3, ERROR_RULING_OPTIONS_MORE_THAN_MAX); // Make sure appeal collateral factors are greater than zero require(_appealCollateralParams[0] > 0 && _appealCollateralParams[1] > 0, ERROR_ZERO_COLLATERAL_FACTOR); // Make sure the given penalty and final round reduction pcts are not greater than 100% require(PctHelpers.isValid(_pcts[0]), ERROR_INVALID_PENALTY_PCT); require(PctHelpers.isValid(_pcts[1]), ERROR_INVALID_FINAL_ROUND_REDUCTION_PCT); // Disputes must request at least one juror to be drafted initially require(_roundParams[5] > 0, ERROR_BAD_INITIAL_JURORS_NUMBER); // Prevent that further rounds have zero jurors require(_roundParams[6] > 0, ERROR_BAD_APPEAL_STEP_FACTOR); // Make sure the max number of appeals allowed does not reach the limit uint256 _maxRegularAppealRounds = _roundParams[7]; bool isMaxAppealRoundsValid = _maxRegularAppealRounds > 0 && _maxRegularAppealRounds <= MAX_REGULAR_APPEAL_ROUNDS_LIMIT; require(isMaxAppealRoundsValid, ERROR_INVALID_MAX_APPEAL_ROUNDS); // Make sure each adjudication round phase duration is valid for (uint i = 0; i < 5; i++) { require(_roundParams[i] > 0 && _roundParams[i] < MAX_ADJ_STATE_DURATION, ERROR_LARGE_ROUND_PHASE_DURATION); } // Make sure min active balance is not zero require(_jurorsParams[0] > 0, ERROR_ZERO_MIN_ACTIVE_BALANCE); // Make sure min max pct of total supply active balance is not zero require(_jurorsParams[1] > 0, ERROR_MIN_MAX_TOTAL_SUPPLY_ZERO); // Make sure the max max pct of total supply active balance is less than 100% require(PctHelpers.isValidHighPrecision(_jurorsParams[2]), ERROR_INVALID_MAX_MAX_TOTAL_SUPPLY_PCT); // Make sure min max pct of total supply active balance is less than the max max pct of total supply active balance require(_jurorsParams[1] < _jurorsParams[2], ERROR_MIN_MORE_THAN_MAX_ACTIVE_PCT); // If there was a config change already scheduled, reset it (in that case we will overwrite last array item). // Otherwise, schedule a new config. if (configChangeTermId > _termId) { configIdByTerm[configChangeTermId] = 0; } else { configs.length++; } uint64 courtConfigId = uint64(configs.length - 1); Config storage config = configs[courtConfigId]; config.fees = FeesConfig({ token: _feeToken, jurorFee: _fees[0], draftFee: _fees[1], settleFee: _fees[2], finalRoundReduction: _pcts[1] }); config.disputes = DisputesConfig({ maxRulingOptions: _maxRulingOptions, evidenceTerms: _roundParams[0], commitTerms: _roundParams[1], revealTerms: _roundParams[2], appealTerms: _roundParams[3], appealConfirmTerms: _roundParams[4], penaltyPct: _pcts[0], firstRoundJurorsNumber: _roundParams[5], appealStepFactor: _roundParams[6], maxRegularAppealRounds: _maxRegularAppealRounds, finalRoundLockTerms: _roundParams[8], appealCollateralFactor: _appealCollateralParams[0], appealConfirmCollateralFactor: _appealCollateralParams[1] }); config.jurors = JurorsConfig({ minActiveBalance: _jurorsParams[0], minMaxPctTotalSupply: _jurorsParams[1], maxMaxPctTotalSupply: _jurorsParams[2], feeTokenTotalSupply: _jurorsParams[3] }); configIdByTerm[_fromTermId] = courtConfigId; configChangeTermId = _fromTermId; emit NewConfig(_fromTermId, courtConfigId); } /** * @dev Internal function to get the Court config for a given term * @param _termId Identification number of the term querying the Court config of * @param _lastEnsuredTermId Identification number of the last ensured term of the Court * @return token Address of the token used to pay for fees * @return fees Array containing: * 0. jurorFee Amount of fee tokens that is paid per juror per dispute * 1. draftFee Amount of fee tokens per juror to cover the drafting cost * 2. settleFee Amount of fee tokens per juror to cover round settlement cost * @return maxRulingOptions Max number of selectable outcomes for each dispute * @return roundParams Array containing durations of phases of a dispute and other params for rounds: * 0. evidenceTerms Max submitting evidence period duration in terms * 1. commitTerms Commit period duration in terms * 2. revealTerms Reveal period duration in terms * 3. appealTerms Appeal period duration in terms * 4. appealConfirmationTerms Appeal confirmation period duration in terms * 5. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 6. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 7. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 8. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @return pcts Array containing: * 0. penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) * 1. finalRoundReduction Permyriad of fee reduction for the last appeal round (‱ - 1/10,000) * @return appealCollateralParams Array containing params for appeal collateral: * 0. appealCollateralFactor Multiple of dispute fees required to appeal a preliminary ruling * 1. appealConfirmCollateralFactor Multiple of dispute fees required to confirm appeal * @return jurorsParams Array containing params for juror registry: * 0. minActiveBalance Minimum amount of juror tokens that can be activated * 1. minMaxPctTotalSupply The min max percent of the total supply a juror can activate, applied for total supply active stake * 2. maxMaxPctTotalSupply The max max percent of the total supply a juror can activate, applied for 0 active stake * 3. feeTokenTotalSupply Set for networks that don't have access to the fee token's total supply, set to 0 for networks that do */ function _getConfigAt(uint64 _termId, uint64 _lastEnsuredTermId) internal view returns ( ERC20 feeToken, uint256[3] memory fees, uint8 maxRulingOptions, uint64[9] memory roundParams, uint16[2] memory pcts, uint256[2] memory appealCollateralParams, uint256[4] memory jurorsParams ) { Config storage config = _getConfigFor(_termId, _lastEnsuredTermId); FeesConfig storage feesConfig = config.fees; feeToken = feesConfig.token; fees = [feesConfig.jurorFee, feesConfig.draftFee, feesConfig.settleFee]; DisputesConfig storage disputesConfig = config.disputes; maxRulingOptions = disputesConfig.maxRulingOptions; roundParams = [ disputesConfig.evidenceTerms, disputesConfig.commitTerms, disputesConfig.revealTerms, disputesConfig.appealTerms, disputesConfig.appealConfirmTerms, disputesConfig.firstRoundJurorsNumber, disputesConfig.appealStepFactor, uint64(disputesConfig.maxRegularAppealRounds), disputesConfig.finalRoundLockTerms ]; pcts = [disputesConfig.penaltyPct, feesConfig.finalRoundReduction]; appealCollateralParams = [disputesConfig.appealCollateralFactor, disputesConfig.appealConfirmCollateralFactor]; JurorsConfig storage jurorsConfig = config.jurors; jurorsParams = [ jurorsConfig.minActiveBalance, jurorsConfig.minMaxPctTotalSupply, jurorsConfig.maxMaxPctTotalSupply, jurorsConfig.feeTokenTotalSupply ]; } /** * @dev Tell the draft config at a certain term * @param _termId Identification number of the term querying the draft config of * @param _lastEnsuredTermId Identification number of the last ensured term of the Court * @return feeToken Address of the token used to pay for fees * @return draftFee Amount of fee tokens per juror to cover the drafting cost * @return penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) */ function _getDraftConfig(uint64 _termId, uint64 _lastEnsuredTermId) internal view returns (ERC20 feeToken, uint256 draftFee, uint16 penaltyPct) { Config storage config = _getConfigFor(_termId, _lastEnsuredTermId); return (config.fees.token, config.fees.draftFee, config.disputes.penaltyPct); } /** * @dev Internal function to get the min active balance config for a given term * @param _termId Identification number of the term querying the min active balance config of * @param _lastEnsuredTermId Identification number of the last ensured term of the Court * @return Minimum amount of juror tokens that can be activated at the given term */ function _getMinActiveBalance(uint64 _termId, uint64 _lastEnsuredTermId) internal view returns (uint256) { Config storage config = _getConfigFor(_termId, _lastEnsuredTermId); return config.jurors.minActiveBalance; } /** * @dev Internal function to get the Court config for a given term * @param _termId Identification number of the term querying the min active balance config of * @param _lastEnsuredTermId Identification number of the last ensured term of the Court * @return Court config for the given term */ function _getConfigFor(uint64 _termId, uint64 _lastEnsuredTermId) internal view returns (Config storage) { uint256 id = _getConfigIdFor(_termId, _lastEnsuredTermId); return configs[id]; } /** * @dev Internal function to get the Court config ID for a given term * @param _termId Identification number of the term querying the Court config of * @param _lastEnsuredTermId Identification number of the last ensured term of the Court * @return Identification number of the config for the given terms */ function _getConfigIdFor(uint64 _termId, uint64 _lastEnsuredTermId) internal view returns (uint256) { // If the given term is lower or equal to the last ensured Court term, it is safe to use a past Court config if (_termId <= _lastEnsuredTermId) { return configIdByTerm[_termId]; } // If the given term is in the future but there is a config change scheduled before it, use the incoming config uint64 scheduledChangeTermId = configChangeTermId; if (scheduledChangeTermId <= _termId) { return configIdByTerm[scheduledChangeTermId]; } // If no changes are scheduled, use the Court config of the last ensured term return configIdByTerm[_lastEnsuredTermId]; } } // File: contracts/court/controller/Controller.sol pragma solidity ^0.5.8; contract Controller is IsContract, CourtClock, CourtConfig { string private constant ERROR_SENDER_NOT_GOVERNOR = "CTR_SENDER_NOT_GOVERNOR"; string private constant ERROR_INVALID_GOVERNOR_ADDRESS = "CTR_INVALID_GOVERNOR_ADDRESS"; string private constant ERROR_IMPLEMENTATION_NOT_CONTRACT = "CTR_IMPLEMENTATION_NOT_CONTRACT"; string private constant ERROR_INVALID_IMPLS_INPUT_LENGTH = "CTR_INVALID_IMPLS_INPUT_LENGTH"; address private constant ZERO_ADDRESS = address(0); // DisputeManager module ID - keccak256(abi.encodePacked("DISPUTE_MANAGER")) bytes32 internal constant DISPUTE_MANAGER = 0x14a6c70f0f6d449c014c7bbc9e68e31e79e8474fb03b7194df83109a2d888ae6; // Treasury module ID - keccak256(abi.encodePacked("TREASURY")) bytes32 internal constant TREASURY = 0x06aa03964db1f7257357ef09714a5f0ca3633723df419e97015e0c7a3e83edb7; // Voting module ID - keccak256(abi.encodePacked("VOTING")) bytes32 internal constant VOTING = 0x7cbb12e82a6d63ff16fe43977f43e3e2b247ecd4e62c0e340da8800a48c67346; // JurorsRegistry module ID - keccak256(abi.encodePacked("JURORS_REGISTRY")) bytes32 internal constant JURORS_REGISTRY = 0x3b21d36b36308c830e6c4053fb40a3b6d79dde78947fbf6b0accd30720ab5370; // Subscriptions module ID - keccak256(abi.encodePacked("SUBSCRIPTIONS")) bytes32 internal constant SUBSCRIPTIONS = 0x2bfa3327fe52344390da94c32a346eeb1b65a8b583e4335a419b9471e88c1365; // BrightIDRegister module ID - keccak256(abi.encodePacked("BRIGHTID_REGISTER")) bytes32 internal constant BRIGHTID_REGISTER = 0xc8d8a5444a51ecc23e5091f18c4162834512a4bc5cae72c637db45c8c37b3329; /** * @dev Governor of the whole system. Set of three addresses to recover funds, change configuration settings and setup modules */ struct Governor { address funds; // This address can be unset at any time. It is allowed to recover funds from the ControlledRecoverable modules address config; // This address is meant not to be unset. It is allowed to change the different configurations of the whole system address feesUpdater;// This is a second address that can update the config. It is expected to be used with a price oracle for updating fees address modules; // This address can be unset at any time. It is allowed to plug/unplug modules from the system } // Governor addresses of the system Governor private governor; // List of modules registered for the system indexed by ID mapping (bytes32 => address) internal modules; event ModuleSet(bytes32 id, address addr); event FundsGovernorChanged(address previousGovernor, address currentGovernor); event ConfigGovernorChanged(address previousGovernor, address currentGovernor); event FeesUpdaterChanged(address previousFeesUpdater, address currentFeesUpdater); event ModulesGovernorChanged(address previousGovernor, address currentGovernor); /** * @dev Ensure the msg.sender is the funds governor */ modifier onlyFundsGovernor { require(msg.sender == governor.funds, ERROR_SENDER_NOT_GOVERNOR); _; } /** * @dev Ensure the msg.sender is the config governor */ modifier onlyConfigGovernor { require(msg.sender == governor.config, ERROR_SENDER_NOT_GOVERNOR); _; } /** * @dev Ensure the msg.sender is the config governor or the fees updater */ modifier onlyConfigGovernorOrFeesUpdater { require(msg.sender == governor.config || msg.sender == governor.feesUpdater, ERROR_SENDER_NOT_GOVERNOR); _; } /** * @dev Ensure the msg.sender is the modules governor */ modifier onlyModulesGovernor { require(msg.sender == governor.modules, ERROR_SENDER_NOT_GOVERNOR); _; } /** * @dev Constructor function * @param _termParams Array containing: * 0. _termDuration Duration in seconds per term * 1. _firstTermStartTime Timestamp in seconds when the court will open (to give time for juror on-boarding) * @param _governors Array containing: * 0. _fundsGovernor Address of the funds governor * 1. _configGovernor Address of the config governor * 2. _feesUpdater Address of the price feesUpdater * 3. _modulesGovernor Address of the modules governor * @param _feeToken Address of the token contract that is used to pay for fees * @param _fees Array containing: * 0. jurorFee Amount of fee tokens that is paid per juror per dispute * 1. draftFee Amount of fee tokens per juror to cover the drafting cost * 2. settleFee Amount of fee tokens per juror to cover round settlement cost * @param _maxRulingOptions Max number of selectable outcomes for each dispute * @param _roundParams Array containing durations of phases of a dispute and other params for rounds: * 0. evidenceTerms Max submitting evidence period duration in terms * 1. commitTerms Commit period duration in terms * 2. revealTerms Reveal period duration in terms * 3. appealTerms Appeal period duration in terms * 4. appealConfirmationTerms Appeal confirmation period duration in terms * 5. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 6. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 7. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 8. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @param _pcts Array containing: * 0. penaltyPct Permyriad of min active tokens balance to be locked to each drafted jurors (‱ - 1/10,000) * 1. finalRoundReduction Permyriad of fee reduction for the last appeal round (‱ - 1/10,000) * @param _appealCollateralParams Array containing params for appeal collateral: * 0. appealCollateralFactor Permyriad multiple of dispute fees required to appeal a preliminary ruling * 1. appealConfirmCollateralFactor Permyriad multiple of dispute fees required to confirm appeal * @param _jurorsParams Array containing params for jurors: * 0. minActiveBalance Minimum amount of juror tokens that can be activated * 1. minMaxPctTotalSupply The min max percent of the total supply a juror can activate, applied for total supply active stake * 2. maxMaxPctTotalSupply The max max percent of the total supply a juror can activate, applied for 0 active stake * 3. feeTokenTotalSupply Set for networks that don't have access to the fee token's total supply, set to 0 for networks that do */ constructor( uint64[2] memory _termParams, address[4] memory _governors, ERC20 _feeToken, uint256[3] memory _fees, uint8 _maxRulingOptions, uint64[9] memory _roundParams, uint16[2] memory _pcts, uint256[2] memory _appealCollateralParams, uint256[4] memory _jurorsParams ) public CourtClock(_termParams, _feeToken) CourtConfig(_feeToken, _fees, _maxRulingOptions, _roundParams, _pcts, _appealCollateralParams, _jurorsParams) { _setFundsGovernor(_governors[0]); _setConfigGovernor(_governors[1]); _setFeesUpdater(_governors[2]); _setModulesGovernor(_governors[3]); } /** * @notice Change Court configuration params * @param _fromTermId Identification number of the term in which the config will be effective at * @param _feeToken Address of the token contract that is used to pay for fees * @param _fees Array containing: * 0. jurorFee Amount of fee tokens that is paid per juror per dispute * 1. draftFee Amount of fee tokens per juror to cover the drafting cost * 2. settleFee Amount of fee tokens per juror to cover round settlement cost * @param _maxRulingOptions Max number of selectable outcomes for each dispute * @param _roundParams Array containing durations of phases of a dispute and other params for rounds: * 0. evidenceTerms Max submitting evidence period duration in terms * 1. commitTerms Commit period duration in terms * 2. revealTerms Reveal period duration in terms * 3. appealTerms Appeal period duration in terms * 4. appealConfirmationTerms Appeal confirmation period duration in terms * 5. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 6. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 7. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 8. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @param _pcts Array containing: * 0. penaltyPct Permyriad of min active tokens balance to be locked to each drafted jurors (‱ - 1/10,000) * 1. finalRoundReduction Permyriad of fee reduction for the last appeal round (‱ - 1/10,000) * @param _appealCollateralParams Array containing params for appeal collateral: * 0. appealCollateralFactor Permyriad multiple of dispute fees required to appeal a preliminary ruling * 1. appealConfirmCollateralFactor Permyriad multiple of dispute fees required to confirm appeal * @param _jurorsParams Array containing params for jurors: * 0. minActiveBalance Minimum amount of juror tokens that can be activated * 1. minMaxPctTotalSupply The min max percent of the total supply a juror can activate, applied for total supply active stake * 2. maxMaxPctTotalSupply The max max percent of the total supply a juror can activate, applied for 0 active stake * 3. feeTokenTotalSupply Set for networks that don't have access to the fee token's total supply, set to 0 for networks that do */ function setConfig( uint64 _fromTermId, ERC20 _feeToken, uint256[3] calldata _fees, uint8 _maxRulingOptions, uint64[9] calldata _roundParams, uint16[2] calldata _pcts, uint256[2] calldata _appealCollateralParams, uint256[4] calldata _jurorsParams ) external onlyConfigGovernorOrFeesUpdater { uint64 currentTermId = _ensureCurrentTerm(); _setConfig( currentTermId, _fromTermId, _feeToken, _fees, _maxRulingOptions, _roundParams, _pcts, _appealCollateralParams, _jurorsParams ); } /** * @notice Delay the Court start time to `_newFirstTermStartTime` * @param _newFirstTermStartTime New timestamp in seconds when the court will open */ function delayStartTime(uint64 _newFirstTermStartTime) external onlyConfigGovernor { _delayStartTime(_newFirstTermStartTime); } /** * @notice Change funds governor address to `_newFundsGovernor` * @param _newFundsGovernor Address of the new funds governor to be set */ function changeFundsGovernor(address _newFundsGovernor) external onlyFundsGovernor { require(_newFundsGovernor != ZERO_ADDRESS, ERROR_INVALID_GOVERNOR_ADDRESS); _setFundsGovernor(_newFundsGovernor); } /** * @notice Change config governor address to `_newConfigGovernor` * @param _newConfigGovernor Address of the new config governor to be set */ function changeConfigGovernor(address _newConfigGovernor) external onlyConfigGovernor { require(_newConfigGovernor != ZERO_ADDRESS, ERROR_INVALID_GOVERNOR_ADDRESS); _setConfigGovernor(_newConfigGovernor); } /** * @notice Change fees updater to `_newFeesUpdater` * @param _newFeesUpdater Address of the new fees updater to be set */ function changeFeesUpdater(address _newFeesUpdater) external onlyConfigGovernor { _setFeesUpdater(_newFeesUpdater); } /** * @notice Change modules governor address to `_newModulesGovernor` * @param _newModulesGovernor Address of the new governor to be set */ function changeModulesGovernor(address _newModulesGovernor) external onlyModulesGovernor { require(_newModulesGovernor != ZERO_ADDRESS, ERROR_INVALID_GOVERNOR_ADDRESS); _setModulesGovernor(_newModulesGovernor); } /** * @notice Remove the funds governor. Set the funds governor to the zero address. * @dev This action cannot be rolled back, once the funds governor has been unset, funds cannot be recovered from recoverable modules anymore */ function ejectFundsGovernor() external onlyFundsGovernor { _setFundsGovernor(ZERO_ADDRESS); } /** * @notice Remove the modules governor. Set the modules governor to the zero address. * @dev This action cannot be rolled back, once the modules governor has been unset, system modules cannot be changed anymore */ function ejectModulesGovernor() external onlyModulesGovernor { _setModulesGovernor(ZERO_ADDRESS); } /** * @notice Set module `_id` to `_addr` * @param _id ID of the module to be set * @param _addr Address of the module to be set */ function setModule(bytes32 _id, address _addr) external onlyModulesGovernor { _setModule(_id, _addr); } /** * @notice Set many modules at once * @param _ids List of ids of each module to be set * @param _addresses List of addressed of each the module to be set */ function setModules(bytes32[] calldata _ids, address[] calldata _addresses) external onlyModulesGovernor { require(_ids.length == _addresses.length, ERROR_INVALID_IMPLS_INPUT_LENGTH); for (uint256 i = 0; i < _ids.length; i++) { _setModule(_ids[i], _addresses[i]); } } /** * @dev Tell the full Court configuration parameters at a certain term * @param _termId Identification number of the term querying the Court config of * @return token Address of the token used to pay for fees * @return fees Array containing: * 0. jurorFee Amount of fee tokens that is paid per juror per dispute * 1. draftFee Amount of fee tokens per juror to cover the drafting cost * 2. settleFee Amount of fee tokens per juror to cover round settlement cost * @return maxRulingOptions Max number of selectable outcomes for each dispute * @return roundParams Array containing durations of phases of a dispute and other params for rounds: * 0. evidenceTerms Max submitting evidence period duration in terms * 1. commitTerms Commit period duration in terms * 2. revealTerms Reveal period duration in terms * 3. appealTerms Appeal period duration in terms * 4. appealConfirmationTerms Appeal confirmation period duration in terms * 5. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 6. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 7. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 8. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @return pcts Array containing: * 0. penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) * 1. finalRoundReduction Permyriad of fee reduction for the last appeal round (‱ - 1/10,000) * @return appealCollateralParams Array containing params for appeal collateral: * 0. appealCollateralFactor Multiple of dispute fees required to appeal a preliminary ruling * 1. appealConfirmCollateralFactor Multiple of dispute fees required to confirm appeal * @return jurorsParams Array containing params for juror registry: * 0. minActiveBalance Minimum amount of juror tokens that can be activated * 1. minMaxPctTotalSupply The min max percent of the total supply a juror can activate, applied for total supply active stake * 2. maxMaxPctTotalSupply The max max percent of the total supply a juror can activate, applied for 0 active stake\ * 3. feeTokenTotalSupply Set for networks that don't have access to the fee token's total supply, set to 0 for networks that do */ function getConfig(uint64 _termId) external view returns ( ERC20 feeToken, uint256[3] memory fees, uint8 maxRulingOptions, uint64[9] memory roundParams, uint16[2] memory pcts, uint256[2] memory appealCollateralParams, uint256[4] memory jurorsParams ) { return _getConfig(_termId); } /** * @dev This function overrides one in the CourtClock, giving the CourtClock access to the config. */ function _getConfig(uint64 _termId) internal view returns ( ERC20 feeToken, uint256[3] memory fees, uint8 maxRulingOptions, uint64[9] memory roundParams, uint16[2] memory pcts, uint256[2] memory appealCollateralParams, uint256[4] memory jurorsParams ) { uint64 lastEnsuredTermId = _lastEnsuredTermId(); return _getConfigAt(_termId, lastEnsuredTermId); } /** * @dev Tell the draft config at a certain term * @param _termId Identification number of the term querying the draft config of * @return feeToken Address of the token used to pay for fees * @return draftFee Amount of fee tokens per juror to cover the drafting cost * @return penaltyPct Permyriad of min active tokens balance to be locked for each drafted juror (‱ - 1/10,000) */ function getDraftConfig(uint64 _termId) external view returns (ERC20 feeToken, uint256 draftFee, uint16 penaltyPct) { uint64 lastEnsuredTermId = _lastEnsuredTermId(); return _getDraftConfig(_termId, lastEnsuredTermId); } /** * @dev Tell the min active balance config at a certain term * @param _termId Identification number of the term querying the min active balance config of * @return Minimum amount of tokens jurors have to activate to participate in the Court */ function getMinActiveBalance(uint64 _termId) external view returns (uint256) { uint64 lastEnsuredTermId = _lastEnsuredTermId(); return _getMinActiveBalance(_termId, lastEnsuredTermId); } /** * @dev Tell the address of the funds governor * @return Address of the funds governor */ function getFundsGovernor() external view returns (address) { return governor.funds; } /** * @dev Tell the address of the config governor * @return Address of the config governor */ function getConfigGovernor() external view returns (address) { return governor.config; } /** * @dev Tell the address of the fees updater * @return Address of the fees updater */ function getFeesUpdater() external view returns (address) { return governor.feesUpdater; } /** * @dev Tell the address of the modules governor * @return Address of the modules governor */ function getModulesGovernor() external view returns (address) { return governor.modules; } /** * @dev Tell address of a module based on a given ID * @param _id ID of the module being queried * @return Address of the requested module */ function getModule(bytes32 _id) external view returns (address) { return _getModule(_id); } /** * @dev Tell the address of the DisputeManager module * @return Address of the DisputeManager module */ function getDisputeManager() external view returns (address) { return _getDisputeManager(); } /** * @dev Tell the address of the Treasury module * @return Address of the Treasury module */ function getTreasury() external view returns (address) { return _getModule(TREASURY); } /** * @dev Tell the address of the Voting module * @return Address of the Voting module */ function getVoting() external view returns (address) { return _getModule(VOTING); } /** * @dev Tell the address of the JurorsRegistry module * @return Address of the JurorsRegistry module */ function getJurorsRegistry() external view returns (address) { return _getModule(JURORS_REGISTRY); } /** * @dev Tell the address of the Subscriptions module * @return Address of the Subscriptions module */ function getSubscriptions() external view returns (address) { return _getSubscriptions(); } /** * @dev Tell the address of the BrightId register * @return Address of the BrightId register */ function getBrightIdRegister() external view returns (address) { return _getBrightIdRegister(); } /** * @dev Internal function to set the address of the funds governor * @param _newFundsGovernor Address of the new config governor to be set */ function _setFundsGovernor(address _newFundsGovernor) internal { emit FundsGovernorChanged(governor.funds, _newFundsGovernor); governor.funds = _newFundsGovernor; } /** * @dev Internal function to set the address of the config governor * @param _newConfigGovernor Address of the new config governor to be set */ function _setConfigGovernor(address _newConfigGovernor) internal { emit ConfigGovernorChanged(governor.config, _newConfigGovernor); governor.config = _newConfigGovernor; } /** * @dev Internal function to set the address of the fees updater * @param _newFeesUpdater Address of the new fees updater to be set */ function _setFeesUpdater(address _newFeesUpdater) internal { emit FeesUpdaterChanged(governor.feesUpdater, _newFeesUpdater); governor.feesUpdater = _newFeesUpdater; } /** * @dev Internal function to set the address of the modules governor * @param _newModulesGovernor Address of the new modules governor to be set */ function _setModulesGovernor(address _newModulesGovernor) internal { emit ModulesGovernorChanged(governor.modules, _newModulesGovernor); governor.modules = _newModulesGovernor; } /** * @dev Internal function to set a module * @param _id Id of the module to be set * @param _addr Address of the module to be set */ function _setModule(bytes32 _id, address _addr) internal { require(isContract(_addr), ERROR_IMPLEMENTATION_NOT_CONTRACT); modules[_id] = _addr; emit ModuleSet(_id, _addr); } /** * @dev Internal function to notify when a term has been transitioned * @param _termId Identification number of the new current term that has been transitioned */ function _onTermTransitioned(uint64 _termId) internal { _ensureTermConfig(_termId); } /** * @dev Internal function to tell the address of the DisputeManager module * @return Address of the DisputeManager module */ function _getDisputeManager() internal view returns (address) { return _getModule(DISPUTE_MANAGER); } /** * @dev Internal function to tell the address of the Subscriptions module * @return Address of the Subscriptions module */ function _getSubscriptions() internal view returns (address) { return _getModule(SUBSCRIPTIONS); } /** * @dev Internal function to tell the address of the BrightId register * @return Address of the BrightId register */ function _getBrightIdRegister() internal view returns (address) { return _getModule(BRIGHTID_REGISTER); } /** * @dev Internal function to tell address of a module based on a given ID * @param _id ID of the module being queried * @return Address of the requested module */ function _getModule(bytes32 _id) internal view returns (address) { return modules[_id]; } } // File: contracts/court/config/ConfigConsumer.sol pragma solidity ^0.5.8; contract ConfigConsumer is CourtConfigData { /** * @dev Internal function to fetch the address of the Config module from the controller * @return Address of the Config module */ function _courtConfig() internal view returns (IConfig); /** * @dev Internal function to get the Court config for a certain term * @param _termId Identification number of the term querying the Court config of * @return Court config for the given term */ function _getConfigAt(uint64 _termId) internal view returns (Config memory) { (ERC20 _feeToken, uint256[3] memory _fees, uint8 maxRulingOptions, uint64[9] memory _roundParams, uint16[2] memory _pcts, uint256[2] memory _appealCollateralParams, uint256[4] memory _jurorsParams) = _courtConfig().getConfig(_termId); Config memory config; config.fees = FeesConfig({ token: _feeToken, jurorFee: _fees[0], draftFee: _fees[1], settleFee: _fees[2], finalRoundReduction: _pcts[1] }); config.disputes = DisputesConfig({ maxRulingOptions: maxRulingOptions, evidenceTerms: _roundParams[0], commitTerms: _roundParams[1], revealTerms: _roundParams[2], appealTerms: _roundParams[3], appealConfirmTerms: _roundParams[4], penaltyPct: _pcts[0], firstRoundJurorsNumber: _roundParams[5], appealStepFactor: _roundParams[6], maxRegularAppealRounds: _roundParams[7], finalRoundLockTerms: _roundParams[8], appealCollateralFactor: _appealCollateralParams[0], appealConfirmCollateralFactor: _appealCollateralParams[1] }); config.jurors = JurorsConfig({ minActiveBalance: _jurorsParams[0], minMaxPctTotalSupply: _jurorsParams[1], maxMaxPctTotalSupply: _jurorsParams[2], feeTokenTotalSupply: _jurorsParams[3] }); return config; } /** * @dev Internal function to get the draft config for a given term * @param _termId Identification number of the term querying the draft config of * @return Draft config for the given term */ function _getDraftConfig(uint64 _termId) internal view returns (DraftConfig memory) { (ERC20 feeToken, uint256 draftFee, uint16 penaltyPct) = _courtConfig().getDraftConfig(_termId); return DraftConfig({ feeToken: feeToken, draftFee: draftFee, penaltyPct: penaltyPct }); } /** * @dev Internal function to get the min active balance config for a given term * @param _termId Identification number of the term querying the min active balance config of * @return Minimum amount of juror tokens that can be activated */ function _getMinActiveBalance(uint64 _termId) internal view returns (uint256) { return _courtConfig().getMinActiveBalance(_termId); } } // File: contracts/treasury/ITreasury.sol pragma solidity ^0.5.8; interface ITreasury { /** * @dev Assign a certain amount of tokens to an account * @param _token ERC20 token to be assigned * @param _to Address of the recipient that will be assigned the tokens to * @param _amount Amount of tokens to be assigned to the recipient */ function assign(ERC20 _token, address _to, uint256 _amount) external; /** * @dev Withdraw a certain amount of tokens * @param _token ERC20 token to be withdrawn * @param _to Address of the recipient that will receive the tokens * @param _amount Amount of tokens to be withdrawn from the sender */ function withdraw(ERC20 _token, address _to, uint256 _amount) external; } // File: contracts/registry/IJurorsRegistry.sol pragma solidity ^0.5.8; interface IJurorsRegistry { /** * @dev Assign a requested amount of juror tokens to a juror * @param _juror Juror to add an amount of tokens to * @param _amount Amount of tokens to be added to the available balance of a juror */ function assignTokens(address _juror, uint256 _amount) external; /** * @dev Burn a requested amount of juror tokens * @param _amount Amount of tokens to be burned */ function burnTokens(uint256 _amount) external; /** * @dev Draft a set of jurors based on given requirements for a term id * @param _params Array containing draft requirements: * 0. bytes32 Term randomness * 1. uint256 Dispute id * 2. uint64 Current term id * 3. uint256 Number of seats already filled * 4. uint256 Number of seats left to be filled * 5. uint64 Number of jurors required for the draft * 6. uint16 Permyriad of the minimum active balance to be locked for the draft * * @return jurors List of jurors selected for the draft * @return length Size of the list of the draft result */ function draft(uint256[7] calldata _params) external returns (address[] memory jurors, uint256 length); /** * @dev Slash a set of jurors based on their votes compared to the winning ruling * @param _termId Current term id * @param _jurors List of juror addresses to be slashed * @param _lockedAmounts List of amounts locked for each corresponding juror that will be either slashed or returned * @param _rewardedJurors List of booleans to tell whether a juror's active balance has to be slashed or not * @return Total amount of slashed tokens */ function slashOrUnlock(uint64 _termId, address[] calldata _jurors, uint256[] calldata _lockedAmounts, bool[] calldata _rewardedJurors) external returns (uint256 collectedTokens); /** * @dev Try to collect a certain amount of tokens from a juror for the next term * @param _juror Juror to collect the tokens from * @param _amount Amount of tokens to be collected from the given juror and for the requested term id * @param _termId Current term id * @return True if the juror has enough unlocked tokens to be collected for the requested term, false otherwise */ function collectTokens(address _juror, uint256 _amount, uint64 _termId) external returns (bool); /** * @dev Lock a juror's withdrawals until a certain term ID * @param _juror Address of the juror to be locked * @param _termId Term ID until which the juror's withdrawals will be locked */ function lockWithdrawals(address _juror, uint64 _termId) external; /** * @dev Tell the active balance of a juror for a given term id * @param _juror Address of the juror querying the active balance of * @param _termId Term ID querying the active balance for * @return Amount of active tokens for juror in the requested past term id */ function activeBalanceOfAt(address _juror, uint64 _termId) external view returns (uint256); /** * @dev Tell the total amount of active juror tokens at the given term id * @param _termId Term ID querying the total active balance for * @return Total amount of active juror tokens at the given term id */ function totalActiveBalanceAt(uint64 _termId) external view returns (uint256); } // File: contracts/brightid/IBrightIdRegister.sol pragma solidity ^0.5.8; contract IBrightIdRegister { function isVerified(address _brightIdUser) external view returns (bool); function hasUniqueUserId(address _brightIdUser) external view returns (bool); function uniqueUserId(address _brightIdUser) external view returns (address); } // File: contracts/arbitration/IArbitrator.sol pragma solidity ^0.5.8; interface IArbitrator { /** * @dev Create a dispute over the Arbitrable sender with a number of possible rulings * @param _possibleRulings Number of possible rulings allowed for the dispute * @param _metadata Optional metadata that can be used to provide additional information on the dispute to be created * @return Dispute identification number */ function createDispute(uint256 _possibleRulings, bytes calldata _metadata) external returns (uint256); /** * @dev Submit evidence for a dispute * @param _disputeId Id of the dispute in the Protocol * @param _submitter Address of the account submitting the evidence * @param _evidence Data submitted for the evidence related to the dispute */ function submitEvidence(uint256 _disputeId, address _submitter, bytes calldata _evidence) external; /** * @dev Close the evidence period of a dispute * @param _disputeId Identification number of the dispute to close its evidence submitting period */ function closeEvidencePeriod(uint256 _disputeId) external; /** * @notice Rule dispute #`_disputeId` if ready * @param _disputeId Identification number of the dispute to be ruled * @return subject Arbitrable instance associated to the dispute * @return ruling Ruling number computed for the given dispute */ function rule(uint256 _disputeId) external returns (address subject, uint256 ruling); /** * @dev Tell the dispute fees information to create a dispute * @return recipient Address where the corresponding dispute fees must be transferred to * @return feeToken ERC20 token used for the fees * @return feeAmount Total amount of fees that must be allowed to the recipient */ function getDisputeFees() external view returns (address recipient, ERC20 feeToken, uint256 feeAmount); } // File: contracts/arbitration/IArbitrable.sol pragma solidity ^0.5.8; contract IArbitrable { /** * @dev Emitted when an IArbitrable instance's dispute is ruled by an IArbitrator * @param arbitrator IArbitrator instance ruling the dispute * @param disputeId Identification number of the dispute being ruled by the arbitrator * @param ruling Ruling given by the arbitrator */ event Ruled(IArbitrator indexed arbitrator, uint256 indexed disputeId, uint256 ruling); } // File: contracts/disputes/IDisputeManager.sol pragma solidity ^0.5.8; interface IDisputeManager { enum DisputeState { PreDraft, Adjudicating, Ruled } enum AdjudicationState { Invalid, Committing, Revealing, Appealing, ConfirmingAppeal, Ended } /** * @dev Create a dispute to be drafted in a future term * @param _subject Arbitrable instance creating the dispute * @param _possibleRulings Number of possible rulings allowed for the drafted jurors to vote on the dispute * @param _metadata Optional metadata that can be used to provide additional information on the dispute to be created * @return Dispute identification number */ function createDispute(IArbitrable _subject, uint8 _possibleRulings, bytes calldata _metadata) external returns (uint256); /** * @dev Submit evidence for a dispute * @param _subject Arbitrable instance submitting the dispute * @param _disputeId Identification number of the dispute receiving new evidence * @param _submitter Address of the account submitting the evidence * @param _evidence Data submitted for the evidence of the dispute */ function submitEvidence(IArbitrable _subject, uint256 _disputeId, address _submitter, bytes calldata _evidence) external; /** * @dev Close the evidence period of a dispute * @param _subject IArbitrable instance requesting to close the evidence submission period * @param _disputeId Identification number of the dispute to close its evidence submitting period */ function closeEvidencePeriod(IArbitrable _subject, uint256 _disputeId) external; /** * @dev Draft jurors for the next round of a dispute * @param _disputeId Identification number of the dispute to be drafted */ function draft(uint256 _disputeId) external; /** * @dev Appeal round of a dispute in favor of a certain ruling * @param _disputeId Identification number of the dispute being appealed * @param _roundId Identification number of the dispute round being appealed * @param _ruling Ruling appealing a dispute round in favor of */ function createAppeal(uint256 _disputeId, uint256 _roundId, uint8 _ruling) external; /** * @dev Confirm appeal for a round of a dispute in favor of a ruling * @param _disputeId Identification number of the dispute confirming an appeal of * @param _roundId Identification number of the dispute round confirming an appeal of * @param _ruling Ruling being confirmed against a dispute round appeal */ function confirmAppeal(uint256 _disputeId, uint256 _roundId, uint8 _ruling) external; /** * @dev Compute the final ruling for a dispute * @param _disputeId Identification number of the dispute to compute its final ruling * @return subject Arbitrable instance associated to the dispute * @return finalRuling Final ruling decided for the given dispute */ function computeRuling(uint256 _disputeId) external returns (IArbitrable subject, uint8 finalRuling); /** * @dev Settle penalties for a round of a dispute * @param _disputeId Identification number of the dispute to settle penalties for * @param _roundId Identification number of the dispute round to settle penalties for * @param _jurorsToSettle Maximum number of jurors to be slashed in this call */ function settlePenalties(uint256 _disputeId, uint256 _roundId, uint256 _jurorsToSettle) external; /** * @dev Claim rewards for a round of a dispute for juror * @dev For regular rounds, it will only reward winning jurors * @param _disputeId Identification number of the dispute to settle rewards for * @param _roundId Identification number of the dispute round to settle rewards for * @param _juror Address of the juror to settle their rewards */ function settleReward(uint256 _disputeId, uint256 _roundId, address _juror) external; /** * @dev Settle appeal deposits for a round of a dispute * @param _disputeId Identification number of the dispute to settle appeal deposits for * @param _roundId Identification number of the dispute round to settle appeal deposits for */ function settleAppealDeposit(uint256 _disputeId, uint256 _roundId) external; /** * @dev Tell the amount of token fees required to create a dispute * @return feeToken ERC20 token used for the fees * @return feeAmount Total amount of fees to be paid for a dispute at the given term */ function getDisputeFees() external view returns (ERC20 feeToken, uint256 feeAmount); /** * @dev Tell information of a certain dispute * @param _disputeId Identification number of the dispute being queried * @return subject Arbitrable subject being disputed * @return possibleRulings Number of possible rulings allowed for the drafted jurors to vote on the dispute * @return state Current state of the dispute being queried: pre-draft, adjudicating, or ruled * @return finalRuling The winning ruling in case the dispute is finished * @return lastRoundId Identification number of the last round created for the dispute * @return createTermId Identification number of the term when the dispute was created */ function getDispute(uint256 _disputeId) external view returns (IArbitrable subject, uint8 possibleRulings, DisputeState state, uint8 finalRuling, uint256 lastRoundId, uint64 createTermId); /** * @dev Tell information of a certain adjudication round * @param _disputeId Identification number of the dispute being queried * @param _roundId Identification number of the round being queried * @return draftTerm Term from which the requested round can be drafted * @return delayedTerms Number of terms the given round was delayed based on its requested draft term id * @return jurorsNumber Number of jurors requested for the round * @return selectedJurors Number of jurors already selected for the requested round * @return settledPenalties Whether or not penalties have been settled for the requested round * @return collectedTokens Amount of juror tokens that were collected from slashed jurors for the requested round * @return coherentJurors Number of jurors that voted in favor of the final ruling in the requested round * @return state Adjudication state of the requested round */ function getRound(uint256 _disputeId, uint256 _roundId) external view returns ( uint64 draftTerm, uint64 delayedTerms, uint64 jurorsNumber, uint64 selectedJurors, uint256 jurorFees, bool settledPenalties, uint256 collectedTokens, uint64 coherentJurors, AdjudicationState state ); /** * @dev Tell appeal-related information of a certain adjudication round * @param _disputeId Identification number of the dispute being queried * @param _roundId Identification number of the round being queried * @return maker Address of the account appealing the given round * @return appealedRuling Ruling confirmed by the appealer of the given round * @return taker Address of the account confirming the appeal of the given round * @return opposedRuling Ruling confirmed by the appeal taker of the given round */ function getAppeal(uint256 _disputeId, uint256 _roundId) external view returns (address maker, uint64 appealedRuling, address taker, uint64 opposedRuling); /** * @dev Tell information related to the next round due to an appeal of a certain round given. * @param _disputeId Identification number of the dispute being queried * @param _roundId Identification number of the round requesting the appeal details of * @return nextRoundStartTerm Term ID from which the next round will start * @return nextRoundJurorsNumber Jurors number for the next round * @return newDisputeState New state for the dispute associated to the given round after the appeal * @return feeToken ERC20 token used for the next round fees * @return jurorFees Total amount of fees to be distributed between the winning jurors of the next round * @return totalFees Total amount of fees for a regular round at the given term * @return appealDeposit Amount to be deposit of fees for a regular round at the given term * @return confirmAppealDeposit Total amount of fees for a regular round at the given term */ function getNextRoundDetails(uint256 _disputeId, uint256 _roundId) external view returns ( uint64 nextRoundStartTerm, uint64 nextRoundJurorsNumber, DisputeState newDisputeState, ERC20 feeToken, uint256 totalFees, uint256 jurorFees, uint256 appealDeposit, uint256 confirmAppealDeposit ); /** * @dev Tell juror-related information of a certain adjudication round * @param _disputeId Identification number of the dispute being queried * @param _roundId Identification number of the round being queried * @param _juror Address of the juror being queried * @return weight Juror weight drafted for the requested round * @return rewarded Whether or not the given juror was rewarded based on the requested round */ function getJuror(uint256 _disputeId, uint256 _roundId, address _juror) external view returns (uint64 weight, bool rewarded); } // File: contracts/court/controller/Controlled.sol pragma solidity ^0.5.8; contract Controlled is IsContract, ConfigConsumer { string private constant ERROR_CONTROLLER_NOT_CONTRACT = "CTD_CONTROLLER_NOT_CONTRACT"; string private constant ERROR_SENDER_NOT_CONTROLLER = "CTD_SENDER_NOT_CONTROLLER"; string private constant ERROR_SENDER_NOT_CONFIG_GOVERNOR = "CTD_SENDER_NOT_CONFIG_GOVERNOR"; string private constant ERROR_SENDER_NOT_DISPUTES_MODULE = "CTD_SENDER_NOT_DISPUTES_MODULE"; // Address of the controller Controller internal controller; /** * @dev Ensure the msg.sender is the controller's config governor */ modifier onlyConfigGovernor { require(msg.sender == _configGovernor(), ERROR_SENDER_NOT_CONFIG_GOVERNOR); _; } /** * @dev Ensure the msg.sender is the controller */ modifier onlyController() { require(msg.sender == address(controller), ERROR_SENDER_NOT_CONTROLLER); _; } /** * @dev Ensure the msg.sender is the DisputeManager module */ modifier onlyDisputeManager() { require(msg.sender == address(_disputeManager()), ERROR_SENDER_NOT_DISPUTES_MODULE); _; } /** * @dev Constructor function * @param _controller Address of the controller */ constructor(Controller _controller) public { require(isContract(address(_controller)), ERROR_CONTROLLER_NOT_CONTRACT); controller = _controller; } /** * @dev Tell the address of the controller * @return Address of the controller */ function getController() external view returns (Controller) { return controller; } /** * @dev Internal function to ensure the Court term is up-to-date, it will try to update it if not * @return Identification number of the current Court term */ function _ensureCurrentTerm() internal returns (uint64) { return _clock().ensureCurrentTerm(); } /** * @dev Internal function to fetch the last ensured term ID of the Court * @return Identification number of the last ensured term */ function _getLastEnsuredTermId() internal view returns (uint64) { return _clock().getLastEnsuredTermId(); } /** * @dev Internal function to tell the current term identification number * @return Identification number of the current term */ function _getCurrentTermId() internal view returns (uint64) { return _clock().getCurrentTermId(); } /** * @dev Internal function to fetch the controller's config governor * @return Address of the controller's governor */ function _configGovernor() internal view returns (address) { return controller.getConfigGovernor(); } /** * @dev Internal function to fetch the address of the DisputeManager module from the controller * @return Address of the DisputeManager module */ function _disputeManager() internal view returns (IDisputeManager) { return IDisputeManager(controller.getDisputeManager()); } /** * @dev Internal function to fetch the address of the Treasury module implementation from the controller * @return Address of the Treasury module implementation */ function _treasury() internal view returns (ITreasury) { return ITreasury(controller.getTreasury()); } /** * @dev Internal function to fetch the address of the Voting module implementation from the controller * @return Address of the Voting module implementation */ function _voting() internal view returns (ICRVoting) { return ICRVoting(controller.getVoting()); } /** * @dev Internal function to fetch the address of the Voting module owner from the controller * @return Address of the Voting module owner */ function _votingOwner() internal view returns (ICRVotingOwner) { return ICRVotingOwner(address(_disputeManager())); } /** * @dev Internal function to fetch the address of the JurorRegistry module implementation from the controller * @return Address of the JurorRegistry module implementation */ function _jurorsRegistry() internal view returns (IJurorsRegistry) { return IJurorsRegistry(controller.getJurorsRegistry()); } /** * @dev Internal function to fetch the address of the BrightId register implementation from the controller * @return Address of the BrightId register implementation */ function _brightIdRegister() internal view returns (IBrightIdRegister) { return IBrightIdRegister(controller.getBrightIdRegister()); } /** * @dev Internal function to fetch the address of the Clock module from the controller * @return Address of the Clock module */ function _clock() internal view returns (IClock) { return IClock(controller); } /** * @dev Internal function to fetch the address of the Config module from the controller * @return Address of the Config module */ function _courtConfig() internal view returns (IConfig) { return IConfig(controller); } } // File: contracts/voting/CRVoting.sol pragma solidity ^0.5.8; contract CRVoting is Controlled, ICRVoting { using SafeMath for uint256; string private constant ERROR_VOTE_ALREADY_EXISTS = "CRV_VOTE_ALREADY_EXISTS"; string private constant ERROR_VOTE_DOES_NOT_EXIST = "CRV_VOTE_DOES_NOT_EXIST"; string private constant ERROR_VOTE_ALREADY_COMMITTED = "CRV_VOTE_ALREADY_COMMITTED"; string private constant ERROR_VOTE_ALREADY_REVEALED = "CRV_VOTE_ALREADY_REVEALED"; string private constant ERROR_INVALID_OUTCOME = "CRV_INVALID_OUTCOME"; string private constant ERROR_INVALID_OUTCOMES_AMOUNT = "CRV_INVALID_OUTCOMES_AMOUNT"; string private constant ERROR_INVALID_COMMITMENT_SALT = "CRV_INVALID_COMMITMENT_SALT"; // Outcome nr. 0 is used to denote a missing vote (default) uint8 internal constant OUTCOME_MISSING = uint8(0); // Outcome nr. 1 is used to denote a leaked vote uint8 internal constant OUTCOME_LEAKED = uint8(1); // Outcome nr. 2 is used to denote a refused vote uint8 internal constant OUTCOME_REFUSED = uint8(2); // Besides the options listed above, every vote instance must provide at least 2 outcomes uint8 internal constant MIN_POSSIBLE_OUTCOMES = uint8(2); // Max number of outcomes excluding the default ones uint8 internal constant MAX_POSSIBLE_OUTCOMES = uint8(-1) - 3; struct CastVote { bytes32 commitment; // Hash of the outcome casted by the voter uint8 outcome; // Outcome submitted by the voter } struct Vote { uint8 winningOutcome; // Outcome winner of a vote instance uint8 maxAllowedOutcome; // Highest outcome allowed for the vote instance mapping (address => CastVote) votes; // Mapping of voters addresses to their casted votes mapping (uint8 => uint256) outcomesTally; // Tally for each of the possible outcomes } // Vote records indexed by their ID mapping (uint256 => Vote) internal voteRecords; event VotingCreated(uint256 indexed voteId, uint8 possibleOutcomes); event VoteCommitted(uint256 indexed voteId, address indexed voter, bytes32 commitment); event VoteRevealed(uint256 indexed voteId, address indexed voter, uint8 outcome, address revealer); event VoteLeaked(uint256 indexed voteId, address indexed voter, uint8 outcome, address leaker); /** * @dev Ensure a certain vote exists * @param _voteId Identification number of the vote to be checked */ modifier voteExists(uint256 _voteId) { Vote storage vote = voteRecords[_voteId]; require(_existsVote(vote), ERROR_VOTE_DOES_NOT_EXIST); _; } /** * @dev Constructor function * @param _controller Address of the controller */ constructor(Controller _controller) Controlled(_controller) public { // solium-disable-previous-line no-empty-blocks } /** * @notice Create a new vote instance with ID #`_voteId` and `_possibleOutcomes` possible outcomes * @dev This function can only be called by the CRVoting owner * @param _voteId ID of the new vote instance to be created * @param _possibleOutcomes Number of possible outcomes for the new vote instance to be created */ function create(uint256 _voteId, uint8 _possibleOutcomes) external onlyDisputeManager { require(_possibleOutcomes >= MIN_POSSIBLE_OUTCOMES && _possibleOutcomes <= MAX_POSSIBLE_OUTCOMES, ERROR_INVALID_OUTCOMES_AMOUNT); Vote storage vote = voteRecords[_voteId]; require(!_existsVote(vote), ERROR_VOTE_ALREADY_EXISTS); // No need for SafeMath: we already checked the number of outcomes above vote.maxAllowedOutcome = OUTCOME_REFUSED + _possibleOutcomes; emit VotingCreated(_voteId, _possibleOutcomes); } /** * @notice Commit a vote for vote #`_voteId` * @param _voteId ID of the vote instance to commit a vote to * @param _commitment Hashed outcome to be stored for future reveal */ function commit(uint256 _voteId, bytes32 _commitment) external voteExists(_voteId) { CastVote storage castVote = voteRecords[_voteId].votes[msg.sender]; require(castVote.commitment == bytes32(0), ERROR_VOTE_ALREADY_COMMITTED); _ensureVoterCanCommit(_voteId, msg.sender); castVote.commitment = _commitment; emit VoteCommitted(_voteId, msg.sender, _commitment); } /** * @notice Leak `_outcome` vote of `_voter` for vote #`_voteId` * @param _voteId ID of the vote instance to leak a vote of * @param _voter Address of the voter to leak a vote of * @param _outcome Outcome leaked for the voter * @param _salt Salt to decrypt and validate the committed vote of the voter */ function leak(uint256 _voteId, address _voter, uint8 _outcome, bytes32 _salt) external voteExists(_voteId) { CastVote storage castVote = voteRecords[_voteId].votes[_voter]; _checkValidSalt(castVote, _outcome, _salt); _ensureCanCommit(_voteId); // There is no need to check if an outcome is valid if it was leaked. // Additionally, leaked votes are not considered for the tally. castVote.outcome = OUTCOME_LEAKED; emit VoteLeaked(_voteId, _voter, _outcome, msg.sender); } /** * @notice Reveal `_outcome` vote of `_voter` for vote #`_voteId` * @param _voteId ID of the vote instance to reveal a vote of * @param _voter Address of the voter to reveal a vote for * @param _outcome Outcome revealed by the voter * @param _salt Salt to decrypt and validate the committed vote of the voter */ function reveal(uint256 _voteId, address _voter, uint8 _outcome, bytes32 _salt) external voteExists(_voteId) { Vote storage vote = voteRecords[_voteId]; CastVote storage castVote = vote.votes[_voter]; _checkValidSalt(castVote, _outcome, _salt); require(_isValidOutcome(vote, _outcome), ERROR_INVALID_OUTCOME); uint256 weight = _ensureVoterCanReveal(_voteId, _voter); castVote.outcome = _outcome; _updateTally(vote, _outcome, weight); emit VoteRevealed(_voteId, _voter, _outcome, msg.sender); } /** * @dev Get the maximum allowed outcome for a given vote instance * @param _voteId ID of the vote instance querying the max allowed outcome of * @return Max allowed outcome for the given vote instance */ function getMaxAllowedOutcome(uint256 _voteId) external view voteExists(_voteId) returns (uint8) { Vote storage vote = voteRecords[_voteId]; return vote.maxAllowedOutcome; } /** * @dev Get the winning outcome of a vote instance. If the winning outcome is missing, which means no one voted in * the given vote instance, it will be considered refused. * @param _voteId ID of the vote instance querying the winning outcome of * @return Winning outcome of the given vote instance or refused in case it's missing */ function getWinningOutcome(uint256 _voteId) external view voteExists(_voteId) returns (uint8) { Vote storage vote = voteRecords[_voteId]; uint8 winningOutcome = vote.winningOutcome; return winningOutcome == OUTCOME_MISSING ? OUTCOME_REFUSED : winningOutcome; } /** * @dev Get the tally of an outcome for a certain vote instance * @param _voteId ID of the vote instance querying the tally of * @param _outcome Outcome querying the tally of * @return Tally of the outcome being queried for the given vote instance */ function getOutcomeTally(uint256 _voteId, uint8 _outcome) external view voteExists(_voteId) returns (uint256) { Vote storage vote = voteRecords[_voteId]; return vote.outcomesTally[_outcome]; } /** * @dev Tell whether an outcome is valid for a given vote instance or not. Missing and leaked outcomes are not considered * valid. The only valid outcomes are refused or any of the custom outcomes of the given vote instance. * @param _voteId ID of the vote instance to check the outcome of * @param _outcome Outcome to check if valid or not * @return True if the given outcome is valid for the requested vote instance, false otherwise. */ function isValidOutcome(uint256 _voteId, uint8 _outcome) external view voteExists(_voteId) returns (bool) { Vote storage vote = voteRecords[_voteId]; return _isValidOutcome(vote, _outcome); } /** * @dev Get the outcome voted by a voter for a certain vote instance * @param _voteId ID of the vote instance querying the outcome of * @param _voter Address of the voter querying the outcome of * @return Outcome of the voter for the given vote instance */ function getVoterOutcome(uint256 _voteId, address _voter) external view voteExists(_voteId) returns (uint8) { Vote storage vote = voteRecords[_voteId]; return vote.votes[_voter].outcome; } /** * @dev Tell whether a voter voted in favor of a certain outcome in a vote instance or not. * @param _voteId ID of the vote instance to query if a voter voted in favor of a certain outcome * @param _outcome Outcome to query if the given voter voted in favor of * @param _voter Address of the voter to query if voted in favor of the given outcome * @return True if the given voter voted in favor of the given outcome, false otherwise */ function hasVotedInFavorOf(uint256 _voteId, uint8 _outcome, address _voter) external view voteExists(_voteId) returns (bool) { Vote storage vote = voteRecords[_voteId]; return vote.votes[_voter].outcome == _outcome; } /** * @dev Filter a list of voters based on whether they voted in favor of a certain outcome in a vote instance or not. * Note that if there was no winning outcome, it means that no one voted, then all voters will be considered * voting against any of the given outcomes. * @param _voteId ID of the vote instance to be checked * @param _outcome Outcome to filter the list of voters of * @param _voters List of addresses of the voters to be filtered * @return List of results to tell whether a voter voted in favor of the given outcome or not */ function getVotersInFavorOf(uint256 _voteId, uint8 _outcome, address[] calldata _voters) external view voteExists(_voteId) returns (bool[] memory) { Vote storage vote = voteRecords[_voteId]; bool[] memory votersInFavor = new bool[](_voters.length); // If there was a winning outcome, filter those voters that voted in favor of the given outcome. for (uint256 i = 0; i < _voters.length; i++) { votersInFavor[i] = _outcome == vote.votes[_voters[i]].outcome; } return votersInFavor; } /** * @dev Hash a vote outcome using a given salt * @param _outcome Outcome to be hashed * @param _salt Encryption salt * @return Hashed outcome */ function hashVote(uint8 _outcome, bytes32 _salt) external pure returns (bytes32) { return _hashVote(_outcome, _salt); } /** * @dev Internal function to ensure votes can be committed for a vote * @param _voteId ID of the vote instance to be checked */ function _ensureCanCommit(uint256 _voteId) internal { ICRVotingOwner owner = _votingOwner(); owner.ensureCanCommit(_voteId); } /** * @dev Internal function to ensure a voter can commit votes * @param _voteId ID of the vote instance to be checked * @param _voter Address of the voter willing to commit a vote */ function _ensureVoterCanCommit(uint256 _voteId, address _voter) internal { ICRVotingOwner owner = _votingOwner(); owner.ensureCanCommit(_voteId, _voter); } /** * @dev Internal function to ensure a voter can reveal votes * @param _voteId ID of the vote instance to be checked * @param _voter Address of the voter willing to reveal a vote * @return Weight of the voter willing to reveal a vote */ function _ensureVoterCanReveal(uint256 _voteId, address _voter) internal returns (uint256) { // There's no need to check voter weight, as this was done on commit ICRVotingOwner owner = _votingOwner(); uint64 weight = owner.ensureCanReveal(_voteId, _voter); return uint256(weight); } /** * @dev Internal function to check if a vote can be revealed for the given outcome and salt * @param _castVote Cast vote to be revealed * @param _outcome Outcome of the cast vote to be proved * @param _salt Salt to decrypt and validate the provided outcome for a cast vote */ function _checkValidSalt(CastVote storage _castVote, uint8 _outcome, bytes32 _salt) internal view { require(_castVote.outcome == OUTCOME_MISSING, ERROR_VOTE_ALREADY_REVEALED); require(_castVote.commitment == _hashVote(_outcome, _salt), ERROR_INVALID_COMMITMENT_SALT); } /** * @dev Internal function to tell whether a certain outcome is valid for a given vote instance or not. Note that * the missing and leaked outcomes are not considered valid. The only outcomes considered valid are refused * or any of the possible outcomes of the given vote instance. This function assumes the given vote exists. * @param _vote Vote instance to check the outcome of * @param _outcome Outcome to check if valid or not * @return True if the given outcome is valid for the requested vote instance, false otherwise. */ function _isValidOutcome(Vote storage _vote, uint8 _outcome) internal view returns (bool) { return _outcome >= OUTCOME_REFUSED && _outcome <= _vote.maxAllowedOutcome; } /** * @dev Internal function to check if a vote instance was already created * @param _vote Vote instance to be checked * @return True if the given vote instance was already created, false otherwise */ function _existsVote(Vote storage _vote) internal view returns (bool) { return _vote.maxAllowedOutcome != OUTCOME_MISSING; } /** * @dev Internal function to hash a vote outcome using a given salt * @param _outcome Outcome to be hashed * @param _salt Encryption salt * @return Hashed outcome */ function _hashVote(uint8 _outcome, bytes32 _salt) internal pure returns (bytes32) { return keccak256(abi.encodePacked(_outcome, _salt)); } /** * @dev Private function to update the tally of a given vote instance based on a new weight in favor of an outcome. * This function assumes the vote instance exists. * @param _vote Vote instance to update the tally of * @param _outcome Outcome of the vote instance to update the tally of * @param _weight Weight to be added to the given outcome of the vote instance */ function _updateTally(Vote storage _vote, uint8 _outcome, uint256 _weight) private { // Check if the given outcome is valid. Missing and leaked votes are ignored for the tally. if (!_isValidOutcome(_vote, _outcome)) { return; } uint256 newOutcomeTally = _vote.outcomesTally[_outcome].add(_weight); _vote.outcomesTally[_outcome] = newOutcomeTally; // Update the winning outcome only if its support was passed or if the given outcome represents a lowest // option than the winning outcome in case of a tie. uint8 winningOutcome = _vote.winningOutcome; uint256 winningOutcomeTally = _vote.outcomesTally[winningOutcome]; if (newOutcomeTally > winningOutcomeTally || (newOutcomeTally == winningOutcomeTally && _outcome < winningOutcome)) { _vote.winningOutcome = _outcome; } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[{"name":"_voteId","type":"uint256"}],"name":"getWinningOutcome","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_voteId","type":"uint256"},{"name":"_voter","type":"address"},{"name":"_outcome","type":"uint8"},{"name":"_salt","type":"bytes32"}],"name":"leak","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_voteId","type":"uint256"},{"name":"_outcome","type":"uint8"},{"name":"_voters","type":"address[]"}],"name":"getVotersInFavorOf","outputs":[{"name":"","type":"bool[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_voteId","type":"uint256"}],"name":"getMaxAllowedOutcome","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getController","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_voteId","type":"uint256"},{"name":"_voter","type":"address"},{"name":"_outcome","type":"uint8"},{"name":"_salt","type":"bytes32"}],"name":"reveal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_voteId","type":"uint256"},{"name":"_outcome","type":"uint8"}],"name":"getOutcomeTally","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_voteId","type":"uint256"},{"name":"_voter","type":"address"}],"name":"getVoterOutcome","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_voteId","type":"uint256"},{"name":"_outcome","type":"uint8"},{"name":"_voter","type":"address"}],"name":"hasVotedInFavorOf","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_outcome","type":"uint8"},{"name":"_salt","type":"bytes32"}],"name":"hashVote","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_voteId","type":"uint256"},{"name":"_outcome","type":"uint8"}],"name":"isValidOutcome","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_voteId","type":"uint256"},{"name":"_commitment","type":"bytes32"}],"name":"commit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_voteId","type":"uint256"},{"name":"_possibleOutcomes","type":"uint8"}],"name":"create","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_controller","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"voteId","type":"uint256"},{"indexed":false,"name":"possibleOutcomes","type":"uint8"}],"name":"VotingCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"voteId","type":"uint256"},{"indexed":true,"name":"voter","type":"address"},{"indexed":false,"name":"commitment","type":"bytes32"}],"name":"VoteCommitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"voteId","type":"uint256"},{"indexed":true,"name":"voter","type":"address"},{"indexed":false,"name":"outcome","type":"uint8"},{"indexed":false,"name":"revealer","type":"address"}],"name":"VoteRevealed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"voteId","type":"uint256"},{"indexed":true,"name":"voter","type":"address"},{"indexed":false,"name":"outcome","type":"uint8"},{"indexed":false,"name":"leaker","type":"address"}],"name":"VoteLeaked","type":"event"}]
Contract Creation Code
60806040523480156200001157600080fd5b506040516020806200174b833981018060405260208110156200003357600080fd5b50518062000048816200014d602090811b901c565b6040518060400160405280601b81526020017f4354445f434f4e54524f4c4c45525f4e4f545f434f4e545241435400000000008152509062000125576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620000e9578181015183820152602001620000cf565b50505050905090810190601f168015620001175780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600080546001600160a01b0319166001600160a01b03929092169190911790555062000172565b60006001600160a01b03821662000167575060006200016d565b50803b15155b919050565b6115c980620001826000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806385dbcf791161008c578063e213137811610066578063e21313781461034c578063e2e7ed9f14610372578063f2f0387714610398578063faf172f7146103bb576100df565b806385dbcf791461029f5780638c8838fb146102d7578063cfa558ba14610303576100df565b80632aee0e66116100bd5780632aee0e66146102235780633018205f146102405780635f38b99c14610264576100df565b8063084d72f4146100e45780630bc67c2b1461011757806318ce8f5614610154575b600080fd5b610101600480360360208110156100fa57600080fd5b50356103e1565b6040805160ff9092168252519081900360200190f35b6101526004803603608081101561012d57600080fd5b508035906001600160a01b036020820135169060ff60408201351690606001356104d7565b005b6101d36004803603606081101561016a57600080fd5b81359160ff6020820135169181019060608101604082013564010000000081111561019457600080fd5b8201836020820111156101a657600080fd5b803590602001918460208302840111640100000000831117156101c857600080fd5b5090925090506105ff565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561020f5781810151838201526020016101f7565b505050509050019250505060405180910390f35b6101016004803603602081101561023957600080fd5b5035610765565b61024861080f565b604080516001600160a01b039092168252519081900360200190f35b6101526004803603608081101561027a57600080fd5b508035906001600160a01b036020820135169060ff604082013516906060013561081e565b6102c5600480360360408110156102b557600080fd5b508035906020013560ff166109eb565b60408051918252519081900360200190f35b610101600480360360408110156102ed57600080fd5b50803590602001356001600160a01b0316610aa1565b6103386004803603606081101561031957600080fd5b50803590602081013560ff1690604001356001600160a01b0316610b5f565b604080519115158252519081900360200190f35b6102c56004803603604081101561036257600080fd5b5060ff8135169060200135610c24565b6103386004803603604081101561038857600080fd5b508035906020013560ff16610c37565b610152600480360360408110156103ae57600080fd5b5080359060200135610cdc565b610152600480360360408110156103d157600080fd5b508035906020013560ff16610e58565b600081815260016020526040812082906103fa8161108d565b60405180604001604052806017815260200160008051602061157e833981519152815250906104aa57604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561046f578181015183820152602001610457565b50505050905090810190601f16801561049c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000848152600160205260409020805460ff1680156104ca57806104cd565b60025b9695505050505050565b600084815260016020526040902084906104f08161108d565b60405180604001604052806017815260200160008051602061157e8339815191528152509061056357604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5060008681526001602081815260408084206001600160a01b038a1685529092019052902061059381868661109b565b61059c876111be565b6001818101805460ff191690911790556040805160ff8716815233602082015281516001600160a01b038916928a927f2a3d1c99ac13aab42ef0ff1a74faaedd1cf1790b9315a93fcb82044d616a4753929081900390910190a350505050505050565b6000848152600160205260409020606090859061061b8161108d565b60405180604001604052806017815260200160008051602061157e8339815191528152509061068e57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50600087815260016020908152604091829020825187815287830281019092019092526060908680156106cb578160200160208202803883390190505b50905060005b86811015610758578260010160008989848181106106eb57fe5b905060200201356001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060010160009054906101000a900460ff1660ff168960ff161482828151811061074057fe5b911515602092830291909101909101526001016106d1565b5098975050505050505050565b6000818152600160205260408120829061077e8161108d565b60405180604001604052806017815260200160008051602061157e833981519152815250906107f157604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50505060009182525060016020526040902054610100900460ff1690565b6000546001600160a01b031690565b600084815260016020526040902084906108378161108d565b60405180604001604052806017815260200160008051602061157e833981519152815250906108aa57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5060008681526001602081815260408084206001600160a01b038a1685529283019091529091206108dc81878761109b565b6108e6828761122c565b6040518060400160405280601381526020017f4352565f494e56414c49445f4f5554434f4d45000000000000000000000000008152509061096b57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5060006109788989611251565b60018301805460ff191660ff8a1617905590506109968388836112ff565b6040805160ff8916815233602082015281516001600160a01b038b16928c927f2531a3609c003cd8a11c3e56f8791d26fec7463d7c89ff80bfb65ca74497b3a4929081900390910190a3505050505050505050565b60008281526001602052604081208390610a048161108d565b60405180604001604052806017815260200160008051602061157e83398151915281525090610a7757604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50505060009283525060016020908152604080842060ff9390931684526002909201905290205490565b60008281526001602052604081208390610aba8161108d565b60405180604001604052806017815260200160008051602061157e83398151915281525090610b2d57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5050506000928352506001602081815260408085206001600160a01b0394909416855292820190529120015460ff1690565b60008381526001602052604081208490610b788161108d565b60405180604001604052806017815260200160008051602061157e83398151915281525090610beb57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5050506000938452506001602081815260408086206001600160a01b03949094168652928201905292209091015460ff91821691161490565b6000610c308383611398565b9392505050565b60008281526001602052604081208390610c508161108d565b60405180604001604052806017815260200160008051602061157e83398151915281525090610cc357604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5060008581526001602052604090206104cd818661122c565b60008281526001602052604090208290610cf58161108d565b60405180604001604052806017815260200160008051602061157e83398151915281525090610d6857604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50600084815260016020818152604080842033855290920181529181902080548251808401909352601a83527f4352565f564f54455f414c52454144595f434f4d4d4954544544000000000000938301939093529115610e0c57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50610e1785336113d0565b838155604080518581529051339187917f1f4e2aa7825ef02e85293e2de66cfbcb326af2632b558996e546bb1ef3e8764d9181900360200190a35050505050565b610e60611459565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090610ef957604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50600260ff821610801590610f12575060fc60ff821611155b6040518060400160405280601b81526020017f4352565f494e56414c49445f4f5554434f4d45535f414d4f554e54000000000081525090610f9757604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b506000828152600160205260409020610faf8161108d565b156040518060400160405280601781526020017f4352565f564f54455f414c52454144595f4558495354530000000000000000008152509061103557604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50805460ff6002840181166101000261ff00199092169190911782556040805191841682525184917f683c4483cc0815ec43f0fbd7ddb39954f33ed12e302e8832a188e26c1e29bbe4919081900360200190a2505050565b54610100900460ff16151590565b600183015460408051808201909152601981527f4352565f564f54455f414c52454144595f52455645414c45440000000000000060208201529060ff161561112757604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b506111328282611398565b835460408051808201909152601b81527f4352565f494e56414c49445f434f4d4d49544d454e545f53414c540000000000602082015291146111b857604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50505050565b60006111c86114d9565b9050806001600160a01b03166315fe5268836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561121057600080fd5b505af1158015611224573d6000803e3d6000fd5b505050505050565b6000600260ff831610801590610c305750509054610100900460ff9081169116111590565b60008061125c6114d9565b90506000816001600160a01b031663c1361a7c86866040518363ffffffff1660e01b815260040180838152602001826001600160a01b03166001600160a01b0316815260200192505050602060405180830381600087803b1580156112c057600080fd5b505af11580156112d4573d6000803e3d6000fd5b505050506040513d60208110156112ea57600080fd5b505167ffffffffffffffff1695945050505050565b611309838361122c565b61131257611393565b60ff82166000908152600284016020526040812054611337908363ffffffff6114e816565b60ff8085166000908152600287016020526040808220849055875490921680825291902054919250908083118061137d5750808314801561137d57508160ff168560ff16105b15611224575050835460ff191660ff8416178455505b505050565b6040805160ff9390931660f81b6020808501919091526021808501939093528151808503909301835260419093019052805191012090565b60006113da6114d9565b9050806001600160a01b03166306349cfa84846040518363ffffffff1660e01b815260040180838152602001826001600160a01b03166001600160a01b0316815260200192505050600060405180830381600087803b15801561143c57600080fd5b505af1158015611450573d6000803e3d6000fd5b50505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b031663db9bee466040518163ffffffff1660e01b815260040160206040518083038186803b1580156114a857600080fd5b505afa1580156114bc573d6000803e3d6000fd5b505050506040513d60208110156114d257600080fd5b5051905090565b60006114e3611459565b905090565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f570000000000000000000000000000006020820152600090838301908482101561157557604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50939250505056fe4352565f564f54455f444f45535f4e4f545f4558495354000000000000000000a165627a7a723058206b36aef97cc38ac48942483cbd5d5108e2f66c4266c72ad2f708ee603d6db3330029000000000000000000000000f0c8376065fadfacb706cafbaac96b321069c015
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100df5760003560e01c806385dbcf791161008c578063e213137811610066578063e21313781461034c578063e2e7ed9f14610372578063f2f0387714610398578063faf172f7146103bb576100df565b806385dbcf791461029f5780638c8838fb146102d7578063cfa558ba14610303576100df565b80632aee0e66116100bd5780632aee0e66146102235780633018205f146102405780635f38b99c14610264576100df565b8063084d72f4146100e45780630bc67c2b1461011757806318ce8f5614610154575b600080fd5b610101600480360360208110156100fa57600080fd5b50356103e1565b6040805160ff9092168252519081900360200190f35b6101526004803603608081101561012d57600080fd5b508035906001600160a01b036020820135169060ff60408201351690606001356104d7565b005b6101d36004803603606081101561016a57600080fd5b81359160ff6020820135169181019060608101604082013564010000000081111561019457600080fd5b8201836020820111156101a657600080fd5b803590602001918460208302840111640100000000831117156101c857600080fd5b5090925090506105ff565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561020f5781810151838201526020016101f7565b505050509050019250505060405180910390f35b6101016004803603602081101561023957600080fd5b5035610765565b61024861080f565b604080516001600160a01b039092168252519081900360200190f35b6101526004803603608081101561027a57600080fd5b508035906001600160a01b036020820135169060ff604082013516906060013561081e565b6102c5600480360360408110156102b557600080fd5b508035906020013560ff166109eb565b60408051918252519081900360200190f35b610101600480360360408110156102ed57600080fd5b50803590602001356001600160a01b0316610aa1565b6103386004803603606081101561031957600080fd5b50803590602081013560ff1690604001356001600160a01b0316610b5f565b604080519115158252519081900360200190f35b6102c56004803603604081101561036257600080fd5b5060ff8135169060200135610c24565b6103386004803603604081101561038857600080fd5b508035906020013560ff16610c37565b610152600480360360408110156103ae57600080fd5b5080359060200135610cdc565b610152600480360360408110156103d157600080fd5b508035906020013560ff16610e58565b600081815260016020526040812082906103fa8161108d565b60405180604001604052806017815260200160008051602061157e833981519152815250906104aa57604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561046f578181015183820152602001610457565b50505050905090810190601f16801561049c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000848152600160205260409020805460ff1680156104ca57806104cd565b60025b9695505050505050565b600084815260016020526040902084906104f08161108d565b60405180604001604052806017815260200160008051602061157e8339815191528152509061056357604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5060008681526001602081815260408084206001600160a01b038a1685529092019052902061059381868661109b565b61059c876111be565b6001818101805460ff191690911790556040805160ff8716815233602082015281516001600160a01b038916928a927f2a3d1c99ac13aab42ef0ff1a74faaedd1cf1790b9315a93fcb82044d616a4753929081900390910190a350505050505050565b6000848152600160205260409020606090859061061b8161108d565b60405180604001604052806017815260200160008051602061157e8339815191528152509061068e57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50600087815260016020908152604091829020825187815287830281019092019092526060908680156106cb578160200160208202803883390190505b50905060005b86811015610758578260010160008989848181106106eb57fe5b905060200201356001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060010160009054906101000a900460ff1660ff168960ff161482828151811061074057fe5b911515602092830291909101909101526001016106d1565b5098975050505050505050565b6000818152600160205260408120829061077e8161108d565b60405180604001604052806017815260200160008051602061157e833981519152815250906107f157604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50505060009182525060016020526040902054610100900460ff1690565b6000546001600160a01b031690565b600084815260016020526040902084906108378161108d565b60405180604001604052806017815260200160008051602061157e833981519152815250906108aa57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5060008681526001602081815260408084206001600160a01b038a1685529283019091529091206108dc81878761109b565b6108e6828761122c565b6040518060400160405280601381526020017f4352565f494e56414c49445f4f5554434f4d45000000000000000000000000008152509061096b57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5060006109788989611251565b60018301805460ff191660ff8a1617905590506109968388836112ff565b6040805160ff8916815233602082015281516001600160a01b038b16928c927f2531a3609c003cd8a11c3e56f8791d26fec7463d7c89ff80bfb65ca74497b3a4929081900390910190a3505050505050505050565b60008281526001602052604081208390610a048161108d565b60405180604001604052806017815260200160008051602061157e83398151915281525090610a7757604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50505060009283525060016020908152604080842060ff9390931684526002909201905290205490565b60008281526001602052604081208390610aba8161108d565b60405180604001604052806017815260200160008051602061157e83398151915281525090610b2d57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5050506000928352506001602081815260408085206001600160a01b0394909416855292820190529120015460ff1690565b60008381526001602052604081208490610b788161108d565b60405180604001604052806017815260200160008051602061157e83398151915281525090610beb57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5050506000938452506001602081815260408086206001600160a01b03949094168652928201905292209091015460ff91821691161490565b6000610c308383611398565b9392505050565b60008281526001602052604081208390610c508161108d565b60405180604001604052806017815260200160008051602061157e83398151915281525090610cc357604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b5060008581526001602052604090206104cd818661122c565b60008281526001602052604090208290610cf58161108d565b60405180604001604052806017815260200160008051602061157e83398151915281525090610d6857604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50600084815260016020818152604080842033855290920181529181902080548251808401909352601a83527f4352565f564f54455f414c52454144595f434f4d4d4954544544000000000000938301939093529115610e0c57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50610e1785336113d0565b838155604080518581529051339187917f1f4e2aa7825ef02e85293e2de66cfbcb326af2632b558996e546bb1ef3e8764d9181900360200190a35050505050565b610e60611459565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090610ef957604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50600260ff821610801590610f12575060fc60ff821611155b6040518060400160405280601b81526020017f4352565f494e56414c49445f4f5554434f4d45535f414d4f554e54000000000081525090610f9757604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b506000828152600160205260409020610faf8161108d565b156040518060400160405280601781526020017f4352565f564f54455f414c52454144595f4558495354530000000000000000008152509061103557604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50805460ff6002840181166101000261ff00199092169190911782556040805191841682525184917f683c4483cc0815ec43f0fbd7ddb39954f33ed12e302e8832a188e26c1e29bbe4919081900360200190a2505050565b54610100900460ff16151590565b600183015460408051808201909152601981527f4352565f564f54455f414c52454144595f52455645414c45440000000000000060208201529060ff161561112757604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b506111328282611398565b835460408051808201909152601b81527f4352565f494e56414c49445f434f4d4d49544d454e545f53414c540000000000602082015291146111b857604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50505050565b60006111c86114d9565b9050806001600160a01b03166315fe5268836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561121057600080fd5b505af1158015611224573d6000803e3d6000fd5b505050505050565b6000600260ff831610801590610c305750509054610100900460ff9081169116111590565b60008061125c6114d9565b90506000816001600160a01b031663c1361a7c86866040518363ffffffff1660e01b815260040180838152602001826001600160a01b03166001600160a01b0316815260200192505050602060405180830381600087803b1580156112c057600080fd5b505af11580156112d4573d6000803e3d6000fd5b505050506040513d60208110156112ea57600080fd5b505167ffffffffffffffff1695945050505050565b611309838361122c565b61131257611393565b60ff82166000908152600284016020526040812054611337908363ffffffff6114e816565b60ff8085166000908152600287016020526040808220849055875490921680825291902054919250908083118061137d5750808314801561137d57508160ff168560ff16105b15611224575050835460ff191660ff8416178455505b505050565b6040805160ff9390931660f81b6020808501919091526021808501939093528151808503909301835260419093019052805191012090565b60006113da6114d9565b9050806001600160a01b03166306349cfa84846040518363ffffffff1660e01b815260040180838152602001826001600160a01b03166001600160a01b0316815260200192505050600060405180830381600087803b15801561143c57600080fd5b505af1158015611450573d6000803e3d6000fd5b50505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b031663db9bee466040518163ffffffff1660e01b815260040160206040518083038186803b1580156114a857600080fd5b505afa1580156114bc573d6000803e3d6000fd5b505050506040513d60208110156114d257600080fd5b5051905090565b60006114e3611459565b905090565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f570000000000000000000000000000006020820152600090838301908482101561157557604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561046f578181015183820152602001610457565b50939250505056fe4352565f564f54455f444f45535f4e4f545f4558495354000000000000000000a165627a7a723058206b36aef97cc38ac48942483cbd5d5108e2f66c4266c72ad2f708ee603d6db3330029
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f0c8376065fadfacb706cafbaac96b321069c015
-----Decoded View---------------
Arg [0] : _controller (address): 0xf0C8376065fadfACB706caFbaaC96B321069C015
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000f0c8376065fadfacb706cafbaac96b321069c015
Deployed Bytecode Sourcemap
120170:16132:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120170:16132:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;127328:292;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;127328:292:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;125040:540;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;125040:540:0;;;-1:-1:-1;;;;;125040:540:0;;;;;;;;;;;;;;;;;:::i;:::-;;130670:569;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;130670:569:0;;;;;;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;130670:569:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;130670:569:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;130670:569:0;;-1:-1:-1;130670:569:0;-1:-1:-1;130670:569:0;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;130670:569:0;;;;;;;;;;;;;;;;;126752:196;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;126752:196:0;;:::i;116424:96::-;;;:::i;:::-;;;;-1:-1:-1;;;;;116424:96:0;;;;;;;;;;;;;;125938:574;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;125938:574:0;;;-1:-1:-1;;;;;125938:574:0;;;;;;;;;;;;;;;;;:::i;127912:215::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;127912:215:0;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;129129:211;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;129129:211:0;;;;;;-1:-1:-1;;;;;129129:211:0;;:::i;129822:240::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;129822:240:0;;;;;;;;;;;;;-1:-1:-1;;;;;129822:240:0;;:::i;:::-;;;;;;;;;;;;;;;;;;131425:133;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;131425:133:0;;;;;;;;;:::i;128617:214::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;128617:214:0;;;;;;;;;:::i;124277:413::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;124277:413:0;;;;;;;:::i;123502:563::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;123502:563:0;;;;;;;;;:::i;127328:292::-;127415:5;122797:20;;;:11;:20;;;;;127397:7;;122836:17;122797:20;122836:11;:17::i;:::-;122855:25;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;122855:25:0;;;122828:53;;;;;-1:-1:-1;;;;;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;127433:17:0;127453:20;;;:11;:20;;;;;127507:19;;;;127544:33;;:68;;127598:14;127544:68;;;121198:1;127544:68;127537:75;127328:292;-1:-1:-1;;;;;;127328:292:0:o;125040:540::-;122777:17;122797:20;;;:11;:20;;;;;125138:7;;122836:17;122797:20;122836:11;:17::i;:::-;122855:25;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;122855:25:0;;;122828:53;;;;;-1:-1:-1;;;;;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;122828:53:0;-1:-1:-1;125158:25:0;125186:20;;;:11;:20;;;;;;;;-1:-1:-1;;;;;125186:34:0;;;;:26;;;:34;;;;125231:42;125186:34;125257:8;125267:5;125231:15;:42::i;:::-;125284:25;125301:7;125284:16;:25::i;:::-;121086:1;125474:16;;;:33;;-1:-1:-1;;125474:33:0;;;;;;125523:49;;;125474:33;125523:49;;;;125561:10;125523:49;;;;;;-1:-1:-1;;;;;125523:49:0;;;125534:7;;125523:49;;;;;;;;;;;122892:1;125040:540;;;;;;:::o;130670:569::-;122777:17;122797:20;;;:11;:20;;;;;130811:13;;130784:7;;122836:17;122797:20;122836:11;:17::i;:::-;122855:25;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;122855:25:0;;;122828:53;;;;;-1:-1:-1;;;;;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;122828:53:0;-1:-1:-1;130842:17:0;130862:20;;;:11;:20;;;;;;;;;130923:26;;;;;;;;;;;;;;;;130893:27;;130934:7;130923:26;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;130923:26:0;-1:-1:-1;130893:56:0;-1:-1:-1;131073:9:0;131068:133;131088:18;;;131068:133;;;131159:4;:10;;:22;131170:7;;131178:1;131170:10;;;;;;;;;;;;;-1:-1:-1;;;;;131170:10:0;-1:-1:-1;;;;;131159:22:0;-1:-1:-1;;;;;131159:22:0;;;;;;;;;;;;:30;;;;;;;;;;;;131147:42;;:8;:42;;;131128:13;131142:1;131128:16;;;;;;;;:61;;;:16;;;;;;;;;;;:61;131108:3;;131068:133;;;-1:-1:-1;131218:13:0;130670:569;-1:-1:-1;;;;;;;;130670:569:0:o;126752:196::-;126842:5;122797:20;;;:11;:20;;;;;126824:7;;122836:17;122797:20;122836:11;:17::i;:::-;122855:25;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;122855:25:0;;;122828:53;;;;;-1:-1:-1;;;;;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;122828:53:0;-1:-1:-1;;;126860:17:0;126880:20;;;-1:-1:-1;126880:11:0;:20;;;;;126918:22;;;;;;;126752:196::o;116424:96::-;116472:10;116502;-1:-1:-1;;;;;116502:10:0;116424:96;:::o;125938:574::-;122777:17;122797:20;;;:11;:20;;;;;126038:7;;122836:17;122797:20;122836:11;:17::i;:::-;122855:25;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;122855:25:0;;;122828:53;;;;;-1:-1:-1;;;;;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;122828:53:0;-1:-1:-1;126058:17:0;126078:20;;;:11;:20;;;;;;;;-1:-1:-1;;;;;126137:18:0;;;;:10;;;:18;;;;;;126166:42;126137:18;126192:8;126202:5;126166:15;:42::i;:::-;126227:31;126243:4;126249:8;126227:15;:31::i;:::-;126260:21;;;;;;;;;;;;;;;;;126219:63;;;;;-1:-1:-1;;;;;126219:63:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;126219:63:0;;126295:14;126312:38;126334:7;126343:6;126312:21;:38::i;:::-;126363:16;;;:27;;-1:-1:-1;;126363:27:0;;;;;;;126295:55;-1:-1:-1;126401:36:0;126414:4;126363:27;126295:55;126401:12;:36::i;:::-;126453:51;;;;;;;;126493:10;126453:51;;;;;;-1:-1:-1;;;;;126453:51:0;;;126466:7;;126453:51;;;;;;;;;;;122892:1;;;125938:574;;;;;;:::o;127912:215::-;128013:7;122797:20;;;:11;:20;;;;;127995:7;;122836:17;122797:20;122836:11;:17::i;:::-;122855:25;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;122855:25:0;;;122828:53;;;;;-1:-1:-1;;;;;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;122828:53:0;-1:-1:-1;;;128033:17:0;128053:20;;;-1:-1:-1;128053:11:0;:20;;;;;;;;128091:28;;;;;;;:18;;;;:28;;;;;;127912:215::o;129129:211::-;129230:5;122797:20;;;:11;:20;;;;;129212:7;;122836:17;122797:20;122836:11;:17::i;:::-;122855:25;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;122855:25:0;;;122828:53;;;;;-1:-1:-1;;;;;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;122828:53:0;-1:-1:-1;;;129248:17:0;129268:20;;;-1:-1:-1;129268:11:0;:20;;;;;;;;-1:-1:-1;;;;;129306:18:0;;;;;;:10;;;:18;;;;:26;;;;;129129:211::o;129822:240::-;129941:4;122797:20;;;:11;:20;;;;;129923:7;;122836:17;122797:20;122836:11;:17::i;:::-;122855:25;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;122855:25:0;;;122828:53;;;;;-1:-1:-1;;;;;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;122828:53:0;-1:-1:-1;;;129958:17:0;129978:20;;;-1:-1:-1;129978:11:0;:20;;;;;;;;-1:-1:-1;;;;;130016:18:0;;;;;;:10;;;:18;;;;:26;;;;:38;;;;:26;;:38;;129822:240::o;131425:133::-;131497:7;131524:26;131534:8;131544:5;131524:9;:26::i;:::-;131517:33;131425:133;-1:-1:-1;;;131425:133:0:o;128617:214::-;128717:4;122797:20;;;:11;:20;;;;;128699:7;;122836:17;122797:20;122836:11;:17::i;:::-;122855:25;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;122855:25:0;;;122828:53;;;;;-1:-1:-1;;;;;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;122828:53:0;-1:-1:-1;128734:17:0;128754:20;;;:11;:20;;;;;128792:31;128754:20;128814:8;128792:15;:31::i;124277:413::-;122777:17;122797:20;;;:11;:20;;;;;124351:7;;122836:17;122797:20;122836:11;:17::i;:::-;122855:25;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;122855:25:0;;;122828:53;;;;;-1:-1:-1;;;;;122828:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;122828:53:0;-1:-1:-1;124371:25:0;124399:20;;;:11;:20;;;;;;;;124426:10;124399:38;;:26;;;:38;;;;;;124456:19;;124491:28;;;;;;;;;;;;;;;;;;;124399:38;124456:33;124448:72;;;;-1:-1:-1;;;;;124448:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;124448:72:0;;124531:42;124553:7;124562:10;124531:21;:42::i;:::-;124586:33;;;124635:47;;;;;;;;124658:10;;124649:7;;124635:47;;;;;;;;;122892:1;124277:413;;;;:::o;123502:563::-;115959:17;:15;:17::i;:::-;-1:-1:-1;;;;;115937:40:0;:10;-1:-1:-1;;;;;115937:40:0;;115979:32;;;;;;;;;;;;;;;;;115929:83;;;;;-1:-1:-1;;;;;115929:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;115929:83:0;-1:-1:-1;121356:1:0;123607:42;;;;;;;:88;;-1:-1:-1;123653:42:0;;;;;;123607:88;123697:29;;;;;;;;;;;;;;;;;123599:128;;;;;-1:-1:-1;;;;;123599:128:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;123599:128:0;-1:-1:-1;123740:17:0;123760:20;;;:11;:20;;;;;123800:17;123760:20;123800:11;:17::i;:::-;123799:18;123819:25;;;;;;;;;;;;;;;;;123791:54;;;;;-1:-1:-1;;;;;123791:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;123791:54:0;-1:-1:-1;123940:60:0;;;121198:1;123965:35;;123940:60;;;;-1:-1:-1;;123940:60:0;;;;;;;;;124016:41;;;;;;;;;124030:7;;124016:41;;;;;;;;;;116023:1;123502:563;;:::o;134477:138::-;134565:23;;;;:42;:23;:42;;;134477:138::o;133178:292::-;133295:17;;;;133333:27;;;;;;;;;;;;;;;;;;133295:36;:17;:36;133287:74;;;;-1:-1:-1;;;;;133287:74:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;133287:74:0;;133404:26;133414:8;133424:5;133404:9;:26::i;:::-;133380:20;;133432:29;;;;;;;;;;;;;;;;;;133380:50;133372:90;;;;-1:-1:-1;;;;;133372:90:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;133372:90:0;;133178:292;;;:::o;131717:149::-;131780:20;131803:14;:12;:14::i;:::-;131780:37;;131828:5;-1:-1:-1;;;;;131828:21:0;;131850:7;131828:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;131828:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;131828:30:0;;;;131717:149;;:::o;134060:182::-;134144:4;121198:1;134168:27;;;;;;;:66;;-1:-1:-1;;134211:23:0;;;;;;;;;134199:35;;;;;134060:182::o;132538:323::-;132620:7;132718:20;132741:14;:12;:14::i;:::-;132718:37;;132766:13;132782:5;-1:-1:-1;;;;;132782:21:0;;132804:7;132813:6;132782:38;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;132782:38:0;-1:-1:-1;;;;;132782:38:0;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;132782:38:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;132782:38:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;132782:38:0;132838:15;;;132538:323;-1:-1:-1;;;;;132538:323:0:o;135394:905::-;135594:32;135610:5;135617:8;135594:15;:32::i;:::-;135589:72;;135643:7;;135589:72;135699:29;;;135673:23;135699:29;;;:19;;;:29;;;;;;:42;;135733:7;135699:42;:33;:42;:::i;:::-;135752:29;;;;;;;;:19;;;:29;;;;;;:47;;;136011:20;;;;;136072:35;;;;;;;135673:68;;-1:-1:-1;136011:20:0;136122:37;;;;:110;;;136183:19;136164:15;:38;:67;;;;;136217:14;136206:25;;:8;:25;;;136164:67;136118:174;;;-1:-1:-1;;136249:31:0;;-1:-1:-1;;136249:31:0;;;;;;;-1:-1:-1;135394:905:0;;;;:::o;134822:152::-;134932:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;134932:33:0;;;;;;134922:44;;;;;;134822:152::o;132083:178::-;132167:20;132190:14;:12;:14::i;:::-;132167:37;;132215:5;-1:-1:-1;;;;;132215:21:0;;132237:7;132246:6;132215:38;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;132215:38:0;-1:-1:-1;;;;;132215:38:0;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;132215:38:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;132215:38:0;;;;132083:178;;;:::o;117818:140::-;117868:15;117919:10;;;;;;;;;-1:-1:-1;;;;;117919:10:0;-1:-1:-1;;;;;117919:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;117919:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117919:30:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;117919:30:0;;-1:-1:-1;117818:140:0;:::o;118745:131::-;118792:14;118849:17;:15;:17::i;:::-;118819:49;;118745:131;:::o;1952:175::-;2079:18;;;;;;;;;;;;;;;;;2012:7;;2044;;;;2070;;;;2062:36;;;;-1:-1:-1;;;;;2062:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;2062:36:0;-1:-1:-1;2118:1:0;1952:175;-1:-1:-1;;;1952:175:0:o
Swarm Source
bzzr://6b36aef97cc38ac48942483cbd5d5108e2f66c4266c72ad2f708ee603d6db333
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.