Polygon Sponsored slots available. Book your slot here!
Contract Overview
My Name Tag:
Not Available, login to update
Txn Hash |
Method
|
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0xf1405ff7c37fbb235fa762689eea4964d048be7fb97a31c16563d05f70f2db69 | Unstake | 23607223 | 434 days 16 hrs ago | 0x9a4b0da9e8e5c7135cd7188bd2e84dac513c594b | IN | 0x517b5c25ee5f972857bd4fd5bffbbd23b1c9bcb7 | 0 MATIC | 0.01276758 | |
0xf0fe2a48507ffdffdfff9d82f3328e7ffeb1b460bae264d6d6f42dafcca0c08b | Deactivate | 23526759 | 436 days 19 hrs ago | 0x9a4b0da9e8e5c7135cd7188bd2e84dac513c594b | IN | 0x517b5c25ee5f972857bd4fd5bffbbd23b1c9bcb7 | 0 MATIC | 0.00491409 | |
0x7447a0ec819ce482de9db5117f83068dc4a4eb65a3fb022add2c0b5c93b7a482 | Stake | 22130461 | 472 days 21 hrs ago | 0x93889f441c03e6e8a662c9c60c750a9bfecb00bd | IN | 0x517b5c25ee5f972857bd4fd5bffbbd23b1c9bcb7 | 0 MATIC | 0.00525939 | |
0x91700d809910b53df9cbaf5137746fb43fae435d133f5a3c3989ee45d8ed0195 | 0x60806040 | 21936399 | 478 days 1 hr ago | 0xdf456b614fe9ff1c7c0b380330da29c96d40fb02 | IN | Create: JurorsRegistry | 0 MATIC | 0.14768586 |
[ Download CSV Export ]
Contract Name:
JurorsRegistry
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/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/lib/os/SafeERC20.sol // Brought from https://github.com/aragon/aragonOS/blob/v4.3.0/contracts/common/SafeERC20.sol // Adapted to use pragma ^0.5.8 and satisfy our linter rules pragma solidity ^0.5.8; library SafeERC20 { // Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`: // https://github.com/ethereum/solidity/issues/3544 bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb; /** * @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false). * Note that this makes an external call to the token. */ function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) { bytes memory transferCallData = abi.encodeWithSelector( TRANSFER_SELECTOR, _to, _amount ); return invokeAndCheckSuccess(address(_token), transferCallData); } /** * @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false). * Note that this makes an external call to the token. */ function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) { bytes memory transferFromCallData = abi.encodeWithSelector( _token.transferFrom.selector, _from, _to, _amount ); return invokeAndCheckSuccess(address(_token), transferFromCallData); } /** * @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false). * Note that this makes an external call to the token. */ function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) { bytes memory approveCallData = abi.encodeWithSelector( _token.approve.selector, _spender, _amount ); return invokeAndCheckSuccess(address(_token), approveCallData); } function invokeAndCheckSuccess(address _addr, bytes memory _calldata) private returns (bool) { bool ret; assembly { let ptr := mload(0x40) // free memory pointer let success := call( gas, // forward all gas _addr, // address 0, // no value add(_calldata, 0x20), // calldata start mload(_calldata), // calldata length ptr, // write output over free memory 0x20 // uint256 return ) if gt(success, 0) { // Check number of bytes returned from last function call switch returndatasize // No bytes returned: assume success case 0 { ret := 1 } // 32 bytes returned: check if non-zero case 0x20 { // Only return success if returned data was true // Already have output in ptr ret := eq(mload(ptr), 1) } // Not sure what was returned: don't mark as success default { } } } return ret; } } // File: contracts/lib/os/SafeMath.sol // 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/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/lib/BytesHelpers.sol pragma solidity ^0.5.8; library BytesHelpers { function toBytes4(bytes memory _self) internal pure returns (bytes4 result) { if (_self.length < 4) { return bytes4(0); } assembly { result := mload(add(_self, 0x20)) } } function toUint256(bytes memory _self, uint256 _location) internal pure returns (uint256 result) { if (_self.length < _location + 32) { // Location + uint256 length. No SafeMath as input is hardcoded return 0; } uint256 realLocation = _location + 32; // Location + bytes array length assembly { result := mload(add(_self, realLocation)) } } // See https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol for a more efficient but risky alternative function extractBytes(bytes memory _self, uint256 _from, uint256 _numberOfBytes) internal pure returns(bytes memory) { if (_self.length < _from + _numberOfBytes) { // No SafeMath as input is hardcoded return new bytes(0); } bytes memory returnValue = new bytes(_numberOfBytes); for (uint256 i = _from; i < _from + _numberOfBytes; i++) { returnValue[i - _from] = _self[i]; } return returnValue; } } // File: contracts/lib/Checkpointing.sol pragma solidity ^0.5.8; /** * @title Checkpointing - Library to handle a historic set of numeric values */ library Checkpointing { uint256 private constant MAX_UINT192 = uint256(uint192(-1)); string private constant ERROR_VALUE_TOO_BIG = "CHECKPOINT_VALUE_TOO_BIG"; string private constant ERROR_CANNOT_ADD_PAST_VALUE = "CHECKPOINT_CANNOT_ADD_PAST_VALUE"; /** * @dev To specify a value at a given point in time, we need to store two values: * - `time`: unit-time value to denote the first time when a value was registered * - `value`: a positive numeric value to registered at a given point in time * * Note that `time` does not need to refer necessarily to a timestamp value, any time unit could be used * for it like block numbers, terms, etc. */ struct Checkpoint { uint64 time; uint192 value; } /** * @dev A history simply denotes a list of checkpoints */ struct History { Checkpoint[] history; } /** * @dev Add a new value to a history for a given point in time. This function does not allow to add values previous * to the latest registered value, if the value willing to add corresponds to the latest registered value, it * will be updated. * @param self Checkpoints history to be altered * @param _time Point in time to register the given value * @param _value Numeric value to be registered at the given point in time */ function add(History storage self, uint64 _time, uint256 _value) internal { require(_value <= MAX_UINT192, ERROR_VALUE_TOO_BIG); _add192(self, _time, uint192(_value)); } /** * @dev Fetch the latest registered value of history, it will return zero if there was no value registered * @param self Checkpoints history to be queried */ function getLast(History storage self) internal view returns (uint256) { uint256 length = self.history.length; if (length > 0) { return uint256(self.history[length - 1].value); } return 0; } /** * @dev Fetch the most recent registered past value of a history based on a given point in time that is not known * how recent it is beforehand. It will return zero if there is no registered value or if given time is * previous to the first registered value. * It uses a binary search. * @param self Checkpoints history to be queried * @param _time Point in time to query the most recent registered past value of */ function get(History storage self, uint64 _time) internal view returns (uint256) { return _binarySearch(self, _time); } /** * @dev Fetch the most recent registered past value of a history based on a given point in time. It will return zero * if there is no registered value or if given time is previous to the first registered value. * It uses a linear search starting from the end. * @param self Checkpoints history to be queried * @param _time Point in time to query the most recent registered past value of */ function getRecent(History storage self, uint64 _time) internal view returns (uint256) { return _backwardsLinearSearch(self, _time); } /** * @dev Private function to add a new value to a history for a given point in time. This function does not allow to * add values previous to the latest registered value, if the value willing to add corresponds to the latest * registered value, it will be updated. * @param self Checkpoints history to be altered * @param _time Point in time to register the given value * @param _value Numeric value to be registered at the given point in time */ function _add192(History storage self, uint64 _time, uint192 _value) private { uint256 length = self.history.length; if (length == 0 || self.history[self.history.length - 1].time < _time) { // If there was no value registered or the given point in time is after the latest registered value, // we can insert it to the history directly. self.history.push(Checkpoint(_time, _value)); } else { // If the point in time given for the new value is not after the latest registered value, we must ensure // we are only trying to update the latest value, otherwise we would be changing past data. Checkpoint storage currentCheckpoint = self.history[length - 1]; require(_time == currentCheckpoint.time, ERROR_CANNOT_ADD_PAST_VALUE); currentCheckpoint.value = _value; } } /** * @dev Private function to execute a backwards linear search to find the most recent registered past value of a * history based on a given point in time. It will return zero if there is no registered value or if given time * is previous to the first registered value. Note that this function will be more suitable when we already know * that the time used to index the search is recent in the given history. * @param self Checkpoints history to be queried * @param _time Point in time to query the most recent registered past value of */ function _backwardsLinearSearch(History storage self, uint64 _time) private view returns (uint256) { // If there was no value registered for the given history return simply zero uint256 length = self.history.length; if (length == 0) { return 0; } uint256 index = length - 1; Checkpoint storage checkpoint = self.history[index]; while (index > 0 && checkpoint.time > _time) { index--; checkpoint = self.history[index]; } return checkpoint.time > _time ? 0 : uint256(checkpoint.value); } /** * @dev Private function execute a binary search to find the most recent registered past value of a history based on * a given point in time. It will return zero if there is no registered value or if given time is previous to * the first registered value. Note that this function will be more suitable when don't know how recent the * time used to index may be. * @param self Checkpoints history to be queried * @param _time Point in time to query the most recent registered past value of */ function _binarySearch(History storage self, uint64 _time) private view returns (uint256) { // If there was no value registered for the given history return simply zero uint256 length = self.history.length; if (length == 0) { return 0; } // If the requested time is equal to or after the time of the latest registered value, return latest value uint256 lastIndex = length - 1; if (_time >= self.history[lastIndex].time) { return uint256(self.history[lastIndex].value); } // If the requested time is previous to the first registered value, return zero to denote missing checkpoint if (_time < self.history[0].time) { return 0; } // Execute a binary search between the checkpointed times of the history uint256 low = 0; uint256 high = lastIndex; while (high > low) { // No need for SafeMath: for this to overflow array size should be ~2^255 uint256 mid = (high + low + 1) / 2; Checkpoint storage checkpoint = self.history[mid]; uint64 midTime = checkpoint.time; if (_time > midTime) { low = mid; } else if (_time < midTime) { // No need for SafeMath: high > low >= 0 => high >= 1 => mid >= 1 high = mid - 1; } else { return uint256(checkpoint.value); } } return uint256(self.history[low].value); } } // File: contracts/lib/HexSumTree.sol pragma solidity ^0.5.8; /** * @title HexSumTree - Library to operate checkpointed 16-ary (hex) sum trees. * @dev A sum tree is a particular case of a tree where the value of a node is equal to the sum of the values of its * children. This library provides a set of functions to operate 16-ary sum trees, i.e. trees where every non-leaf * node has 16 children and its value is equivalent to the sum of the values of all of them. Additionally, a * checkpointed tree means that each time a value on a node is updated, its previous value will be saved to allow * accessing historic information. * * Example of a checkpointed binary sum tree: * * CURRENT PREVIOUS * * Level 2 100 ---------------------------------------- 70 * ______|_______ ______|_______ * / \ / \ * Level 1 34 66 ------------------------- 23 47 * _____|_____ _____|_____ _____|_____ _____|_____ * / \ / \ / \ / \ * Level 0 22 12 53 13 ----------- 22 1 17 30 * */ library HexSumTree { using SafeMath for uint256; using Checkpointing for Checkpointing.History; string private constant ERROR_UPDATE_OVERFLOW = "SUM_TREE_UPDATE_OVERFLOW"; string private constant ERROR_KEY_DOES_NOT_EXIST = "SUM_TREE_KEY_DOES_NOT_EXIST"; string private constant ERROR_SEARCH_OUT_OF_BOUNDS = "SUM_TREE_SEARCH_OUT_OF_BOUNDS"; string private constant ERROR_MISSING_SEARCH_VALUES = "SUM_TREE_MISSING_SEARCH_VALUES"; // Constants used to perform tree computations // To change any the following constants, the following relationship must be kept: 2^BITS_IN_NIBBLE = CHILDREN // The max depth of the tree will be given by: BITS_IN_NIBBLE * MAX_DEPTH = 256 (so in this case it's 64) uint256 private constant CHILDREN = 16; uint256 private constant BITS_IN_NIBBLE = 4; // All items are leaves, inserted at height or level zero. The root height will be increasing as new levels are inserted in the tree. uint256 private constant ITEMS_LEVEL = 0; // Tree nodes are identified with a 32-bytes length key. Leaves are identified with consecutive incremental keys // starting with 0x0000000000000000000000000000000000000000000000000000000000000000, while non-leaf nodes' keys // are computed based on their level and their children keys. uint256 private constant BASE_KEY = 0; // Timestamp used to checkpoint the first value of the tree height during initialization uint64 private constant INITIALIZATION_INITIAL_TIME = uint64(0); /** * @dev The tree is stored using the following structure: * - nodes: A mapping indexed by a pair (level, key) with a history of the values for each node (level -> key -> value). * - height: A history of the heights of the tree. Minimum height is 1, a root with 16 children. * - nextKey: The next key to be used to identify the next new value that will be inserted into the tree. */ struct Tree { uint256 nextKey; Checkpointing.History height; mapping (uint256 => mapping (uint256 => Checkpointing.History)) nodes; } /** * @dev Search params to traverse the tree caching previous results: * - time: Point in time to query the values being searched, this value shouldn't change during a search * - level: Level being analyzed for the search, it starts at the level under the root and decrements till the leaves * - parentKey: Key of the parent of the nodes being analyzed at the given level for the search * - foundValues: Number of values in the list being searched that were already found, it will go from 0 until the size of the list * - visitedTotal: Total sum of values that were already visited during the search, it will go from 0 until the tree total */ struct SearchParams { uint64 time; uint256 level; uint256 parentKey; uint256 foundValues; uint256 visitedTotal; } /** * @dev Initialize tree setting the next key and first height checkpoint */ function init(Tree storage self) internal { self.height.add(INITIALIZATION_INITIAL_TIME, ITEMS_LEVEL + 1); self.nextKey = BASE_KEY; } /** * @dev Insert a new item to the tree at given point in time * @param _time Point in time to register the given value * @param _value New numeric value to be added to the tree * @return Unique key identifying the new value inserted */ function insert(Tree storage self, uint64 _time, uint256 _value) internal returns (uint256) { // As the values are always stored in the leaves of the tree (level 0), the key to index each of them will be // always incrementing, starting from zero. Add a new level if necessary. uint256 key = self.nextKey++; _addLevelIfNecessary(self, key, _time); // If the new value is not zero, first set the value of the new leaf node, then add a new level at the top of // the tree if necessary, and finally update sums cached in all the non-leaf nodes. if (_value > 0) { _add(self, ITEMS_LEVEL, key, _time, _value); _updateSums(self, key, _time, _value, true); } return key; } /** * @dev Set the value of a leaf node indexed by its key at given point in time * @param _time Point in time to set the given value * @param _key Key of the leaf node to be set in the tree * @param _value New numeric value to be set for the given key */ function set(Tree storage self, uint256 _key, uint64 _time, uint256 _value) internal { require(_key < self.nextKey, ERROR_KEY_DOES_NOT_EXIST); // Set the new value for the requested leaf node uint256 lastValue = getItem(self, _key); _add(self, ITEMS_LEVEL, _key, _time, _value); // Update sums cached in the non-leaf nodes. Note that overflows are being checked at the end of the whole update. if (_value > lastValue) { _updateSums(self, _key, _time, _value - lastValue, true); } else if (_value < lastValue) { _updateSums(self, _key, _time, lastValue - _value, false); } } /** * @dev Update the value of a non-leaf node indexed by its key at given point in time based on a delta * @param _key Key of the leaf node to be updated in the tree * @param _time Point in time to update the given value * @param _delta Numeric delta to update the value of the given key * @param _positive Boolean to tell whether the given delta should be added to or subtracted from the current value */ function update(Tree storage self, uint256 _key, uint64 _time, uint256 _delta, bool _positive) internal { require(_key < self.nextKey, ERROR_KEY_DOES_NOT_EXIST); // Update the value of the requested leaf node based on the given delta uint256 lastValue = getItem(self, _key); uint256 newValue = _positive ? lastValue.add(_delta) : lastValue.sub(_delta); _add(self, ITEMS_LEVEL, _key, _time, newValue); // Update sums cached in the non-leaf nodes. Note that overflows is being checked at the end of the whole update. _updateSums(self, _key, _time, _delta, _positive); } /** * @dev Search a list of values in the tree at a given point in time. It will return a list with the nearest * high value in case a value cannot be found. This function assumes the given list of given values to be * searched is in ascending order. In case of searching a value out of bounds, it will return zeroed results. * @param _values Ordered list of values to be searched in the tree * @param _time Point in time to query the values being searched * @return keys List of keys found for each requested value in the same order * @return values List of node values found for each requested value in the same order */ function search(Tree storage self, uint256[] memory _values, uint64 _time) internal view returns (uint256[] memory keys, uint256[] memory values) { require(_values.length > 0, ERROR_MISSING_SEARCH_VALUES); // Throw out-of-bounds error if there are no items in the tree or the highest value being searched is greater than the total uint256 total = getRecentTotalAt(self, _time); // No need for SafeMath: positive length of array already checked require(total > 0 && total > _values[_values.length - 1], ERROR_SEARCH_OUT_OF_BOUNDS); // Build search params for the first iteration uint256 rootLevel = getRecentHeightAt(self, _time); SearchParams memory searchParams = SearchParams(_time, rootLevel.sub(1), BASE_KEY, 0, 0); // These arrays will be used to fill in the results. We are passing them as parameters to avoid extra copies uint256 length = _values.length; keys = new uint256[](length); values = new uint256[](length); _search(self, _values, searchParams, keys, values); } /** * @dev Tell the sum of the all the items (leaves) stored in the tree, i.e. value of the root of the tree */ function getTotal(Tree storage self) internal view returns (uint256) { uint256 rootLevel = getHeight(self); return getNode(self, rootLevel, BASE_KEY); } /** * @dev Tell the sum of the all the items (leaves) stored in the tree, i.e. value of the root of the tree, at a given point in time * It uses a binary search for the root node, a linear one for the height. * @param _time Point in time to query the sum of all the items (leaves) stored in the tree */ function getTotalAt(Tree storage self, uint64 _time) internal view returns (uint256) { uint256 rootLevel = getRecentHeightAt(self, _time); return getNodeAt(self, rootLevel, BASE_KEY, _time); } /** * @dev Tell the sum of the all the items (leaves) stored in the tree, i.e. value of the root of the tree, at a given point in time * It uses a linear search starting from the end. * @param _time Point in time to query the sum of all the items (leaves) stored in the tree */ function getRecentTotalAt(Tree storage self, uint64 _time) internal view returns (uint256) { uint256 rootLevel = getRecentHeightAt(self, _time); return getRecentNodeAt(self, rootLevel, BASE_KEY, _time); } /** * @dev Tell the value of a certain leaf indexed by a given key * @param _key Key of the leaf node querying the value of */ function getItem(Tree storage self, uint256 _key) internal view returns (uint256) { return getNode(self, ITEMS_LEVEL, _key); } /** * @dev Tell the value of a certain leaf indexed by a given key at a given point in time * It uses a binary search. * @param _key Key of the leaf node querying the value of * @param _time Point in time to query the value of the requested leaf */ function getItemAt(Tree storage self, uint256 _key, uint64 _time) internal view returns (uint256) { return getNodeAt(self, ITEMS_LEVEL, _key, _time); } /** * @dev Tell the value of a certain node indexed by a given (level,key) pair * @param _level Level of the node querying the value of * @param _key Key of the node querying the value of */ function getNode(Tree storage self, uint256 _level, uint256 _key) internal view returns (uint256) { return self.nodes[_level][_key].getLast(); } /** * @dev Tell the value of a certain node indexed by a given (level,key) pair at a given point in time * It uses a binary search. * @param _level Level of the node querying the value of * @param _key Key of the node querying the value of * @param _time Point in time to query the value of the requested node */ function getNodeAt(Tree storage self, uint256 _level, uint256 _key, uint64 _time) internal view returns (uint256) { return self.nodes[_level][_key].get(_time); } /** * @dev Tell the value of a certain node indexed by a given (level,key) pair at a given point in time * It uses a linear search starting from the end. * @param _level Level of the node querying the value of * @param _key Key of the node querying the value of * @param _time Point in time to query the value of the requested node */ function getRecentNodeAt(Tree storage self, uint256 _level, uint256 _key, uint64 _time) internal view returns (uint256) { return self.nodes[_level][_key].getRecent(_time); } /** * @dev Tell the height of the tree */ function getHeight(Tree storage self) internal view returns (uint256) { return self.height.getLast(); } /** * @dev Tell the height of the tree at a given point in time * It uses a linear search starting from the end. * @param _time Point in time to query the height of the tree */ function getRecentHeightAt(Tree storage self, uint64 _time) internal view returns (uint256) { return self.height.getRecent(_time); } /** * @dev Private function to update the values of all the ancestors of the given leaf node based on the delta updated * @param _key Key of the leaf node to update the ancestors of * @param _time Point in time to update the ancestors' values of the given leaf node * @param _delta Numeric delta to update the ancestors' values of the given leaf node * @param _positive Boolean to tell whether the given delta should be added to or subtracted from ancestors' values */ function _updateSums(Tree storage self, uint256 _key, uint64 _time, uint256 _delta, bool _positive) private { uint256 mask = uint256(-1); uint256 ancestorKey = _key; uint256 currentHeight = getHeight(self); for (uint256 level = ITEMS_LEVEL + 1; level <= currentHeight; level++) { // Build a mask to get the key of the ancestor at a certain level. For example: // Level 0: leaves don't have children // Level 1: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0 (up to 16 leaves) // Level 2: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 (up to 32 leaves) // ... // Level 63: 0x0000000000000000000000000000000000000000000000000000000000000000 (up to 16^64 leaves - tree max height) mask = mask << BITS_IN_NIBBLE; // The key of the ancestor at that level "i" is equivalent to the "(64 - i)-th" most significant nibbles // of the ancestor's key of the previous level "i - 1". Thus, we can compute the key of an ancestor at a // certain level applying the mask to the ancestor's key of the previous level. Note that for the first // iteration, the key of the ancestor of the previous level is simply the key of the leaf being updated. ancestorKey = ancestorKey & mask; // Update value uint256 lastValue = getNode(self, level, ancestorKey); uint256 newValue = _positive ? lastValue.add(_delta) : lastValue.sub(_delta); _add(self, level, ancestorKey, _time, newValue); } // Check if there was an overflow. Note that we only need to check the value stored in the root since the // sum only increases going up through the tree. require(!_positive || getNode(self, currentHeight, ancestorKey) >= _delta, ERROR_UPDATE_OVERFLOW); } /** * @dev Private function to add a new level to the tree based on a new key that will be inserted * @param _newKey New key willing to be inserted in the tree * @param _time Point in time when the new key will be inserted */ function _addLevelIfNecessary(Tree storage self, uint256 _newKey, uint64 _time) private { uint256 currentHeight = getHeight(self); if (_shouldAddLevel(currentHeight, _newKey)) { // Max height allowed for the tree is 64 since we are using node keys of 32 bytes. However, note that we // are not checking if said limit has been hit when inserting new leaves to the tree, for the purpose of // this system having 2^256 items inserted is unrealistic. uint256 newHeight = currentHeight + 1; uint256 rootValue = getNode(self, currentHeight, BASE_KEY); _add(self, newHeight, BASE_KEY, _time, rootValue); self.height.add(_time, newHeight); } } /** * @dev Private function to register a new value in the history of a node at a given point in time * @param _level Level of the node to add a new value at a given point in time to * @param _key Key of the node to add a new value at a given point in time to * @param _time Point in time to register a value for the given node * @param _value Numeric value to be registered for the given node at a given point in time */ function _add(Tree storage self, uint256 _level, uint256 _key, uint64 _time, uint256 _value) private { self.nodes[_level][_key].add(_time, _value); } /** * @dev Recursive pre-order traversal function * Every time it checks a node, it traverses the input array to find the initial subset of elements that are * below its accumulated value and passes that sub-array to the next iteration. Actually, the array is always * the same, to avoid making extra copies, it just passes the number of values already found , to avoid * checking values that went through a different branch. The same happens with the result lists of keys and * values, these are the same on every recursion step. The visited total is carried over each iteration to * avoid having to subtract all elements in the array. * @param _values Ordered list of values to be searched in the tree * @param _params Search parameters for the current recursive step * @param _resultKeys List of keys found for each requested value in the same order * @param _resultValues List of node values found for each requested value in the same order */ function _search( Tree storage self, uint256[] memory _values, SearchParams memory _params, uint256[] memory _resultKeys, uint256[] memory _resultValues ) private view { uint256 levelKeyLessSignificantNibble = _params.level.mul(BITS_IN_NIBBLE); for (uint256 childNumber = 0; childNumber < CHILDREN; childNumber++) { // Return if we already found enough values if (_params.foundValues >= _values.length) { break; } // Build child node key shifting the child number to the position of the less significant nibble of // the keys for the level being analyzed, and adding it to the key of the parent node. For example, // for a tree with height 5, if we are checking the children of the second node of the level 3, whose // key is 0x0000000000000000000000000000000000000000000000000000000000001000, its children keys are: // Child 0: 0x0000000000000000000000000000000000000000000000000000000000001000 // Child 1: 0x0000000000000000000000000000000000000000000000000000000000001100 // Child 2: 0x0000000000000000000000000000000000000000000000000000000000001200 // ... // Child 15: 0x0000000000000000000000000000000000000000000000000000000000001f00 uint256 childNodeKey = _params.parentKey.add(childNumber << levelKeyLessSignificantNibble); uint256 childNodeValue = getRecentNodeAt(self, _params.level, childNodeKey, _params.time); // Check how many values belong to the subtree of this node. As they are ordered, it will be a contiguous // subset starting from the beginning, so we only need to know the length of that subset. uint256 newVisitedTotal = _params.visitedTotal.add(childNodeValue); uint256 subtreeIncludedValues = _getValuesIncludedInSubtree(_values, _params.foundValues, newVisitedTotal); // If there are some values included in the subtree of the child node, visit them if (subtreeIncludedValues > 0) { // If the child node being analyzed is a leaf, add it to the list of results a number of times equals // to the number of values that were included in it. Otherwise, descend one level. if (_params.level == ITEMS_LEVEL) { _copyFoundNode(_params.foundValues, subtreeIncludedValues, childNodeKey, _resultKeys, childNodeValue, _resultValues); } else { SearchParams memory nextLevelParams = SearchParams( _params.time, _params.level - 1, // No need for SafeMath: we already checked above that the level being checked is greater than zero childNodeKey, _params.foundValues, _params.visitedTotal ); _search(self, _values, nextLevelParams, _resultKeys, _resultValues); } // Update the number of values that were already found _params.foundValues = _params.foundValues.add(subtreeIncludedValues); } // Update the visited total for the next node in this level _params.visitedTotal = newVisitedTotal; } } /** * @dev Private function to check if a new key can be added to the tree based on the current height of the tree * @param _currentHeight Current height of the tree to check if it supports adding the given key * @param _newKey Key willing to be added to the tree with the given current height * @return True if the current height of the tree should be increased to add the new key, false otherwise. */ function _shouldAddLevel(uint256 _currentHeight, uint256 _newKey) private pure returns (bool) { // Build a mask that will match all the possible keys for the given height. For example: // Height 1: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0 (up to 16 keys) // Height 2: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 (up to 32 keys) // ... // Height 64: 0x0000000000000000000000000000000000000000000000000000000000000000 (up to 16^64 keys - tree max height) uint256 shift = _currentHeight.mul(BITS_IN_NIBBLE); uint256 mask = uint256(-1) << shift; // Check if the given key can be represented in the tree with the current given height using the mask. return (_newKey & mask) != 0; } /** * @dev Private function to tell how many values of a list can be found in a subtree * @param _values List of values being searched in ascending order * @param _foundValues Number of values that were already found and should be ignore * @param _subtreeTotal Total sum of the given subtree to check the numbers that are included in it * @return Number of values in the list that are included in the given subtree */ function _getValuesIncludedInSubtree(uint256[] memory _values, uint256 _foundValues, uint256 _subtreeTotal) private pure returns (uint256) { // Look for all the values that can be found in the given subtree uint256 i = _foundValues; while (i < _values.length && _values[i] < _subtreeTotal) { i++; } return i - _foundValues; } /** * @dev Private function to copy a node a given number of times to a results list. This function assumes the given * results list have enough size to support the requested copy. * @param _from Index of the results list to start copying the given node * @param _times Number of times the given node will be copied * @param _key Key of the node to be copied * @param _resultKeys Lists of key results to copy the given node key to * @param _value Value of the node to be copied * @param _resultValues Lists of value results to copy the given node value to */ function _copyFoundNode( uint256 _from, uint256 _times, uint256 _key, uint256[] memory _resultKeys, uint256 _value, uint256[] memory _resultValues ) private pure { for (uint256 i = 0; i < _times; i++) { _resultKeys[_from + i] = _key; _resultValues[_from + i] = _value; } } } // 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/lib/JurorsTreeSortition.sol pragma solidity ^0.5.8; /** * @title JurorsTreeSortition - Library to perform jurors sortition over a `HexSumTree` */ library JurorsTreeSortition { using SafeMath for uint256; using HexSumTree for HexSumTree.Tree; string private constant ERROR_INVALID_INTERVAL_SEARCH = "TREE_INVALID_INTERVAL_SEARCH"; string private constant ERROR_SORTITION_LENGTHS_MISMATCH = "TREE_SORTITION_LENGTHS_MISMATCH"; /** * @dev Search random items in the tree based on certain restrictions * @param _termRandomness Randomness to compute the seed for the draft * @param _disputeId Identification number of the dispute to draft jurors for * @param _termId Current term when the draft is being computed * @param _selectedJurors Number of jurors already selected for the draft * @param _batchRequestedJurors Number of jurors to be selected in the given batch of the draft * @param _roundRequestedJurors Total number of jurors requested to be drafted * @param _sortitionIteration Number of sortitions already performed for the given draft * @return jurorsIds List of juror ids obtained based on the requested search * @return jurorsBalances List of active balances for each juror obtained based on the requested search */ function batchedRandomSearch( HexSumTree.Tree storage tree, bytes32 _termRandomness, uint256 _disputeId, uint64 _termId, uint256 _selectedJurors, uint256 _batchRequestedJurors, uint256 _roundRequestedJurors, uint256 _sortitionIteration ) internal view returns (uint256[] memory jurorsIds, uint256[] memory jurorsBalances) { (uint256 low, uint256 high) = getSearchBatchBounds(tree, _termId, _selectedJurors, _batchRequestedJurors, _roundRequestedJurors); uint256[] memory balances = _computeSearchRandomBalances( _termRandomness, _disputeId, _sortitionIteration, _batchRequestedJurors, low, high ); (jurorsIds, jurorsBalances) = tree.search(balances, _termId); require(jurorsIds.length == jurorsBalances.length, ERROR_SORTITION_LENGTHS_MISMATCH); require(jurorsIds.length == _batchRequestedJurors, ERROR_SORTITION_LENGTHS_MISMATCH); } /** * @dev Get the bounds for a draft batch based on the active balances of the jurors * @param _termId Term ID of the active balances that will be used to compute the boundaries * @param _selectedJurors Number of jurors already selected for the draft * @param _batchRequestedJurors Number of jurors to be selected in the given batch of the draft * @param _roundRequestedJurors Total number of jurors requested to be drafted * @return low Low bound to be used for the sortition to draft the requested number of jurors for the given batch * @return high High bound to be used for the sortition to draft the requested number of jurors for the given batch */ function getSearchBatchBounds( HexSumTree.Tree storage tree, uint64 _termId, uint256 _selectedJurors, uint256 _batchRequestedJurors, uint256 _roundRequestedJurors ) internal view returns (uint256 low, uint256 high) { uint256 totalActiveBalance = tree.getRecentTotalAt(_termId); low = _selectedJurors.mul(totalActiveBalance).div(_roundRequestedJurors); uint256 newSelectedJurors = _selectedJurors.add(_batchRequestedJurors); high = newSelectedJurors.mul(totalActiveBalance).div(_roundRequestedJurors); } /** * @dev Get a random list of active balances to be searched in the jurors tree for a given draft batch * @param _termRandomness Randomness to compute the seed for the draft * @param _disputeId Identification number of the dispute to draft jurors for (for randomness) * @param _sortitionIteration Number of sortitions already performed for the given draft (for randomness) * @param _batchRequestedJurors Number of jurors to be selected in the given batch of the draft * @param _lowBatchBound Low bound to be used for the sortition batch to draft the requested number of jurors * @param _highBatchBound High bound to be used for the sortition batch to draft the requested number of jurors * @return Random list of active balances to be searched in the jurors tree for the given draft batch */ function _computeSearchRandomBalances( bytes32 _termRandomness, uint256 _disputeId, uint256 _sortitionIteration, uint256 _batchRequestedJurors, uint256 _lowBatchBound, uint256 _highBatchBound ) internal pure returns (uint256[] memory) { // Calculate the interval to be used to search the balances in the tree. Since we are using a modulo function to compute the // random balances to be searched, intervals will be closed on the left and open on the right, for example [0,10). require(_highBatchBound > _lowBatchBound, ERROR_INVALID_INTERVAL_SEARCH); uint256 interval = _highBatchBound - _lowBatchBound; // Compute an ordered list of random active balance to be searched in the jurors tree uint256[] memory balances = new uint256[](_batchRequestedJurors); for (uint256 batchJurorNumber = 0; batchJurorNumber < _batchRequestedJurors; batchJurorNumber++) { // Compute a random seed using: // - The inherent randomness associated to the term from blockhash // - The disputeId, so 2 disputes in the same term will have different outcomes // - The sortition iteration, to avoid getting stuck if resulting jurors are dismissed due to locked balance // - The juror number in this batch bytes32 seed = keccak256(abi.encodePacked(_termRandomness, _disputeId, _sortitionIteration, batchJurorNumber)); // Compute a random active balance to be searched in the jurors tree using the generated seed within the // boundaries computed for the current batch. balances[batchJurorNumber] = _lowBatchBound.add(uint256(seed) % interval); // Make sure it's ordered, flip values if necessary for (uint256 i = batchJurorNumber; i > 0 && balances[i] < balances[i - 1]; i--) { uint256 tmp = balances[i - 1]; balances[i - 1] = balances[i]; balances[i] = tmp; } } return balances; } } // File: contracts/standards/ERC900.sol pragma solidity ^0.5.8; // Interface for ERC900: https://eips.ethereum.org/EIPS/eip-900 interface ERC900 { event Staked(address indexed user, uint256 amount, uint256 total, bytes data); event Unstaked(address indexed user, uint256 amount, uint256 total, bytes data); /** * @dev Stake a certain amount of tokens * @param _amount Amount of tokens to be staked * @param _data Optional data that can be used to add signalling information in more complex staking applications */ function stake(uint256 _amount, bytes calldata _data) external; /** * @dev Stake a certain amount of tokens in favor of someone * @param _user Address to stake an amount of tokens to * @param _amount Amount of tokens to be staked * @param _data Optional data that can be used to add signalling information in more complex staking applications */ function stakeFor(address _user, uint256 _amount, bytes calldata _data) external; /** * @dev Unstake a certain amount of tokens * @param _amount Amount of tokens to be unstaked * @param _data Optional data that can be used to add signalling information in more complex staking applications */ function unstake(uint256 _amount, bytes calldata _data) external; /** * @dev Tell the total amount of tokens staked for an address * @param _addr Address querying the total amount of tokens staked for * @return Total amount of tokens staked for an address */ function totalStakedFor(address _addr) external view returns (uint256); /** * @dev Tell the total amount of tokens staked * @return Total amount of tokens staked */ function totalStaked() external view returns (uint256); /** * @dev Tell the address of the token used for staking * @return Address of the token used for staking */ function token() external view returns (address); /* * @dev Tell if the current registry supports historic information or not * @return True if the optional history functions are implemented, false otherwise */ function supportsHistory() external pure returns (bool); } // File: contracts/standards/ApproveAndCall.sol pragma solidity ^0.5.8; interface ApproveAndCallFallBack { /** * @dev This allows users to use their tokens to interact with contracts in one function call instead of two * @param _from Address of the account transferring the tokens * @param _amount The amount of tokens approved for in the transfer * @param _token Address of the token contract calling this function * @param _data Optional data that can be used to add signalling information in more complex staking applications */ function receiveApproval(address _from, uint256 _amount, address _token, bytes calldata _data) external; } // 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/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/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/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/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/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/court/controller/ControlledRecoverable.sol pragma solidity ^0.5.8; contract ControlledRecoverable is Controlled { using SafeERC20 for ERC20; string private constant ERROR_SENDER_NOT_FUNDS_GOVERNOR = "CTD_SENDER_NOT_FUNDS_GOVERNOR"; string private constant ERROR_INSUFFICIENT_RECOVER_FUNDS = "CTD_INSUFFICIENT_RECOVER_FUNDS"; string private constant ERROR_RECOVER_TOKEN_FUNDS_FAILED = "CTD_RECOVER_TOKEN_FUNDS_FAILED"; event RecoverFunds(ERC20 token, address recipient, uint256 balance); /** * @dev Ensure the msg.sender is the controller's funds governor */ modifier onlyFundsGovernor { require(msg.sender == controller.getFundsGovernor(), ERROR_SENDER_NOT_FUNDS_GOVERNOR); _; } /** * @dev Constructor function * @param _controller Address of the controller */ constructor(Controller _controller) Controlled(_controller) public { // solium-disable-previous-line no-empty-blocks } /** * @notice Transfer all `_token` tokens to `_to` * @param _token ERC20 token to be recovered * @param _to Address of the recipient that will be receive all the funds of the requested token */ function recoverFunds(ERC20 _token, address _to) external onlyFundsGovernor { uint256 balance = _token.balanceOf(address(this)); require(balance > 0, ERROR_INSUFFICIENT_RECOVER_FUNDS); require(_token.safeTransfer(_to, balance), ERROR_RECOVER_TOKEN_FUNDS_FAILED); emit RecoverFunds(_token, _to, balance); } } // File: contracts/brightid/RegisterAndCall.sol pragma solidity ^0.5.8; contract RegisterAndCall { /** * @dev This allows users to verify their BrightId account and interact with a contract in one transaction. * Implementers of this function should check that msg.sender is the BrightIdRegister contract expected. * @param _usersSenderAddress The address from which the transaction was created * @param _usersUniqueId The unique address assigned to the registered BrightId user * @param _data Optional data that can be used to determine what operations to execute in the recipient contract */ function receiveRegistration(address _usersSenderAddress, address _usersUniqueId, bytes calldata _data) external; } // File: contracts/registry/JurorsRegistry.sol pragma solidity ^0.5.8; contract JurorsRegistry is ControlledRecoverable, IJurorsRegistry, ERC900, ApproveAndCallFallBack, RegisterAndCall { using SafeERC20 for ERC20; using SafeMath for uint256; using PctHelpers for uint256; using BytesHelpers for bytes; using HexSumTree for HexSumTree.Tree; using JurorsTreeSortition for HexSumTree.Tree; string private constant ERROR_NOT_CONTRACT = "JR_NOT_CONTRACT"; string private constant ERROR_INVALID_ZERO_AMOUNT = "JR_INVALID_ZERO_AMOUNT"; string private constant ERROR_INVALID_ACTIVATION_AMOUNT = "JR_INVALID_ACTIVATION_AMOUNT"; string private constant ERROR_INVALID_DEACTIVATION_AMOUNT = "JR_INVALID_DEACTIVATION_AMOUNT"; string private constant ERROR_INVALID_LOCKED_AMOUNTS_LENGTH = "JR_INVALID_LOCKED_AMOUNTS_LEN"; string private constant ERROR_INVALID_REWARDED_JURORS_LENGTH = "JR_INVALID_REWARDED_JURORS_LEN"; string private constant ERROR_ACTIVE_BALANCE_BELOW_MIN = "JR_ACTIVE_BALANCE_BELOW_MIN"; string private constant ERROR_ACTIVE_BALANCE_ABOVE_MAX = "JR_ACTIVE_BALANCE_ABOVE_MAX"; string private constant ERROR_NOT_ENOUGH_AVAILABLE_BALANCE = "JR_NOT_ENOUGH_AVAILABLE_BALANCE"; string private constant ERROR_CANNOT_REDUCE_DEACTIVATION_REQUEST = "JR_CANT_REDUCE_DEACTIVATION_REQ"; string private constant ERROR_TOKEN_TRANSFER_FAILED = "JR_TOKEN_TRANSFER_FAILED"; string private constant ERROR_TOKEN_APPROVE_NOT_ALLOWED = "JR_TOKEN_APPROVE_NOT_ALLOWED"; string private constant ERROR_BAD_TOTAL_ACTIVE_BALANCE_LIMIT = "JR_BAD_TOTAL_ACTIVE_BAL_LIMIT"; string private constant ERROR_TOTAL_ACTIVE_BALANCE_TOO_LOW = "JR_TOTAL_ACTIVE_BALANCE_TOO_LOW"; string private constant ERROR_TOTAL_ACTIVE_BALANCE_EXCEEDED = "JR_TOTAL_ACTIVE_BALANCE_EXCEEDED"; string private constant ERROR_WITHDRAWALS_LOCK = "JR_WITHDRAWALS_LOCK"; string private constant ERROR_SENDER_NOT_BRIGHTID_REGISTER = "JR_SENDER_NOT_BRIGHTID_REGISTER"; string private constant ERROR_NO_FUNCTION_MATCH = "JR_NO_FUNCTION_MATCH"; // Address that will be used to burn juror tokens address internal constant BURN_ACCOUNT = address(0x000000000000000000000000000000000000dEaD); address internal constant ZERO_ADDRESS = address(0); // Maximum number of sortition iterations allowed per draft call uint256 internal constant MAX_DRAFT_ITERATIONS = 10; /** * @dev Jurors have three kind of balances, these are: * - active: tokens activated for the Court that can be locked in case the juror is drafted * - locked: amount of active tokens that are locked for a draft * - available: tokens that are not activated for the Court and can be withdrawn by the juror at any time * * Due to a gas optimization for drafting, the "active" tokens are stored in a `HexSumTree`, while the others * are stored in this contract as `lockedBalance` and `availableBalance` respectively. Given that the jurors' * active balances cannot be affected during the current Court term, if jurors want to deactivate some of their * active tokens, their balance will be updated for the following term, and they won't be allowed to * withdraw them until the current term has ended. * * Note that even though jurors balances are stored separately, all the balances are held by this contract. */ struct Juror { uint256 id; // Key in the jurors tree used for drafting uint256 lockedBalance; // Maximum amount of tokens that can be slashed based on the juror's drafts uint256 availableBalance; // Available tokens that can be withdrawn at any time uint64 withdrawalsLockTermId; // Term ID until which the juror's withdrawals will be locked DeactivationRequest deactivationRequest; // Juror's pending deactivation request } /** * @dev Given that the jurors balances cannot be affected during a Court term, if jurors want to deactivate some * of their tokens, the tree will always be updated for the following term, and they won't be able to * withdraw the requested amount until the current term has finished. Thus, we need to keep track the term * when a token deactivation was requested and its corresponding amount. */ struct DeactivationRequest { uint256 amount; // Amount requested for deactivation uint64 availableTermId; // Term ID when jurors can withdraw their requested deactivation tokens } /** * @dev Internal struct to wrap all the params required to perform jurors drafting */ struct DraftParams { bytes32 termRandomness; // Randomness seed to be used for the draft uint256 disputeId; // ID of the dispute being drafted uint64 termId; // Term ID of the dispute's draft term uint256 selectedJurors; // Number of jurors already selected for the draft uint256 batchRequestedJurors; // Number of jurors to be selected in the given batch of the draft uint256 roundRequestedJurors; // Total number of jurors requested to be drafted uint256 draftLockAmount; // Amount of tokens to be locked to each drafted juror uint256 iteration; // Sortition iteration number } // Maximum amount of total active balance that can be held in the registry uint256 internal totalActiveBalanceLimit; // Juror ERC20 token ERC20 internal jurorsToken; // Mapping of juror data indexed by address mapping (address => Juror) internal jurorsByAddress; // Mapping of juror addresses indexed by id mapping (uint256 => address) internal jurorsAddressById; // Tree to store jurors active balance by term for the drafting process HexSumTree.Tree internal tree; // Mapping of unique juror address from the BrightIdRegister to their currently total active stake mapping (address => uint256) internal brightIdActiveStake; event JurorActivated(address indexed juror, uint64 fromTermId, uint256 amount, address sender); event JurorDeactivationRequested(address indexed juror, uint64 availableTermId, uint256 amount); event JurorDeactivationProcessed(address indexed juror, uint64 availableTermId, uint256 amount, uint64 processedTermId); event JurorDeactivationUpdated(address indexed juror, uint64 availableTermId, uint256 amount, uint64 updateTermId); event JurorBalanceLocked(address indexed juror, uint256 amount); event JurorBalanceUnlocked(address indexed juror, uint256 amount); event JurorSlashed(address indexed juror, uint256 amount, uint64 effectiveTermId); event JurorTokensAssigned(address indexed juror, uint256 amount); event JurorTokensBurned(uint256 amount); event JurorTokensCollected(address indexed juror, uint256 amount, uint64 effectiveTermId); event TotalActiveBalanceLimitChanged(uint256 previousTotalActiveBalanceLimit, uint256 currentTotalActiveBalanceLimit); /** * @dev Constructor function * @param _controller Address of the controller * @param _totalActiveBalanceLimit Maximum amount of total active balance that can be held in the registry */ constructor(Controller _controller, uint256 _totalActiveBalanceLimit) ControlledRecoverable(_controller) public { // No need to explicitly call `Controlled` constructor since `ControlledRecoverable` is already doing it jurorsToken = _getConfigAt(0).fees.token; _setTotalActiveBalanceLimit(_totalActiveBalanceLimit); tree.init(); // First tree item is an empty juror assert(tree.insert(0, 0) == 0); } /** * @notice Activate `_amount == 0 ? 'all available tokens' : @tokenAmount(self.token(), _amount)` for the next term * @param _amount Amount of juror tokens to be activated for the next term */ function activate(uint256 _amount) external { _activateTokens(msg.sender, _amount, msg.sender); } /** * @notice Deactivate `_amount == 0 ? 'all unlocked tokens' : @tokenAmount(self.token(), _amount)` for the next term * @param _amount Amount of juror tokens to be deactivated for the next term */ function deactivate(uint256 _amount) external { uint64 termId = _ensureCurrentTerm(); Juror storage juror = jurorsByAddress[msg.sender]; uint256 unlockedActiveBalance = _lastUnlockedActiveBalanceOf(juror); uint256 amountToDeactivate = _amount == 0 ? unlockedActiveBalance : _amount; require(amountToDeactivate > 0, ERROR_INVALID_ZERO_AMOUNT); require(amountToDeactivate <= unlockedActiveBalance, ERROR_INVALID_DEACTIVATION_AMOUNT); // No need for SafeMath: we already checked values above uint256 futureActiveBalance = unlockedActiveBalance - amountToDeactivate; uint256 minActiveBalance = _getMinActiveBalance(termId); require(futureActiveBalance == 0 || futureActiveBalance >= minActiveBalance, ERROR_INVALID_DEACTIVATION_AMOUNT); _createDeactivationRequest(msg.sender, amountToDeactivate); } /** * @notice Stake `@tokenAmount(self.token(), _amount)` for the sender to the Court * @param _amount Amount of tokens to be staked * @param _data Optional data that can be used to request the activation of the transferred tokens */ function stake(uint256 _amount, bytes calldata _data) external { _stake(msg.sender, msg.sender, _amount, _data); } /** * @notice Stake `@tokenAmount(self.token(), _amount)` for `_to` to the Court * @param _to Address to stake an amount of tokens to * @param _amount Amount of tokens to be staked * @param _data Optional data that can be used to request the activation of the transferred tokens */ function stakeFor(address _to, uint256 _amount, bytes calldata _data) external { _stake(msg.sender, _to, _amount, _data); } /** * @notice Unstake `@tokenAmount(self.token(), _amount)` for `_to` from the Court * @param _amount Amount of tokens to be unstaked * @param _data Optional data is never used by this function, only logged */ function unstake(uint256 _amount, bytes calldata _data) external { _unstake(msg.sender, _amount, _data); } /** * @dev Callback of approveAndCall, allows staking directly with a transaction to the token contract. * @param _from Address making the transfer * @param _amount Amount of tokens to transfer * @param _token Address of the token * @param _data Optional data that can be used to request the activation of the transferred tokens */ function receiveApproval(address _from, uint256 _amount, address _token, bytes calldata _data) external { require(msg.sender == _token && _token == address(jurorsToken), ERROR_TOKEN_APPROVE_NOT_ALLOWED); _stake(_from, _from, _amount, _data); } /** * @dev The user just verified and registered themselves in the BrightIdRegister, check the function call in _data, * extract the params and execute it. * @param _jurorSenderAddress The address from which the transaction was created * @param _jurorUniqueId The unique address assigned to the registered BrightId user * @param _data Data used to determine what function to call */ function receiveRegistration(address _jurorSenderAddress, address _jurorUniqueId, bytes calldata _data) external { require(msg.sender == address(_brightIdRegister()), ERROR_SENDER_NOT_BRIGHTID_REGISTER); bytes4 functionSelector = _data.toBytes4(); uint256 amount = _data.toUint256(4); // amountLocation: 4 (from end of sig) if (functionSelector == JurorsRegistry(this).activate.selector) { _activateTokens(_jurorSenderAddress, amount, _jurorSenderAddress); } else if (functionSelector == JurorsRegistry(this).stake.selector) { bytes memory callData = _data.extractBytes(100, 4); // callDataLocation: 4 + 32 + 32 + 32 = 100 (sig + uint256 _amount + callData location + callData length) _stake(_jurorSenderAddress, _jurorSenderAddress, amount, callData); } else { revert(ERROR_NO_FUNCTION_MATCH); } } /** * @notice Process a token deactivation requested for `_juror` if there is any * @param _juror Address of the juror to process the deactivation request of */ function processDeactivationRequest(address _juror) external { uint64 termId = _ensureCurrentTerm(); _processDeactivationRequest(_juror, termId); } /** * @notice Assign `@tokenAmount(self.token(), _amount)` to the available balance of `_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 onlyDisputeManager { if (_amount > 0) { _updateAvailableBalanceOf(_juror, _amount, true); emit JurorTokensAssigned(_juror, _amount); } } /** * @notice Burn `@tokenAmount(self.token(), _amount)` * @param _amount Amount of tokens to be burned */ function burnTokens(uint256 _amount) external onlyDisputeManager { if (_amount > 0) { _updateAvailableBalanceOf(BURN_ACCOUNT, _amount, true); emit JurorTokensBurned(_amount); } } /** * @notice 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 onlyDisputeManager returns (address[] memory jurors, uint256 length) { DraftParams memory draftParams = _buildDraftParams(_params); jurors = new address[](draftParams.batchRequestedJurors); // Jurors returned by the tree multi-sortition may not have enough unlocked active balance to be drafted. Thus, // we compute several sortitions until all the requested jurors are selected. To guarantee a different set of // jurors on each sortition, the iteration number will be part of the random seed to be used in the sortition. // Note that we are capping the number of iterations to avoid an OOG error, which means that this function could // return less jurors than the requested number. for (draftParams.iteration = 0; length < draftParams.batchRequestedJurors && draftParams.iteration < MAX_DRAFT_ITERATIONS; draftParams.iteration++ ) { (uint256[] memory jurorIds, uint256[] memory activeBalances) = _treeSearch(draftParams); for (uint256 i = 0; i < jurorIds.length && length < draftParams.batchRequestedJurors; i++) { // We assume the selected jurors are registered in the registry, we are not checking their addresses exist address jurorAddress = jurorsAddressById[jurorIds[i]]; Juror storage juror = jurorsByAddress[jurorAddress]; // Compute new locked balance for a juror based on the penalty applied when being drafted uint256 newLockedBalance = juror.lockedBalance.add(draftParams.draftLockAmount); // Check if there is any deactivation requests for the next term. Drafts are always computed for the current term // but we have to make sure we are locking an amount that will exist in the next term. uint256 nextTermDeactivationRequestAmount = _deactivationRequestedAmountForTerm(juror, draftParams.termId + 1); // Check if juror has enough active tokens to lock the requested amount for the draft, skip it otherwise. uint256 currentActiveBalance = activeBalances[i]; if (currentActiveBalance >= newLockedBalance) { // Check if the amount of active tokens for the next term is enough to lock the required amount for // the draft. Otherwise, reduce the requested deactivation amount of the next term. // Next term deactivation amount should always be less than current active balance, but we make sure using SafeMath uint256 nextTermActiveBalance = currentActiveBalance.sub(nextTermDeactivationRequestAmount); if (nextTermActiveBalance < newLockedBalance) { // No need for SafeMath: we already checked values above _reduceDeactivationRequest(jurorAddress, newLockedBalance - nextTermActiveBalance, draftParams.termId); } // Update the current active locked balance of the juror juror.lockedBalance = newLockedBalance; jurors[length++] = jurorAddress; emit JurorBalanceLocked(jurorAddress, draftParams.draftLockAmount); } } } } /** * @notice Slash a set of jurors based on their votes compared to the winning ruling. This function will unlock the * corresponding locked balances of those jurors that are set to be slashed. * @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 onlyDisputeManager returns (uint256) { require(_jurors.length == _lockedAmounts.length, ERROR_INVALID_LOCKED_AMOUNTS_LENGTH); require(_jurors.length == _rewardedJurors.length, ERROR_INVALID_REWARDED_JURORS_LENGTH); uint64 nextTermId = _termId + 1; uint256 collectedTokens; for (uint256 i = 0; i < _jurors.length; i++) { uint256 lockedAmount = _lockedAmounts[i]; address jurorAddress = _jurors[i]; Juror storage juror = jurorsByAddress[jurorAddress]; juror.lockedBalance = juror.lockedBalance.sub(lockedAmount); // Slash juror if requested. Note that there's no need to check if there was a deactivation // request since we're working with already locked balances. if (_rewardedJurors[i]) { emit JurorBalanceUnlocked(jurorAddress, lockedAmount); } else { collectedTokens = collectedTokens.add(lockedAmount); _updateBrightIdActiveStake(jurorAddress, lockedAmount, false); tree.update(juror.id, nextTermId, lockedAmount, false); emit JurorSlashed(jurorAddress, lockedAmount, nextTermId); } } return collectedTokens; } /** * @notice Try to collect `@tokenAmount(self.token(), _amount)` from `_juror` for the term #`_termId + 1`. * @dev This function tries to decrease the active balance of a juror for the next term based on the requested * amount. It can be seen as a way to early-slash a juror's active balance. * @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 onlyDisputeManager returns (bool) { if (_amount == 0) { return true; } uint64 nextTermId = _termId + 1; Juror storage juror = jurorsByAddress[_juror]; uint256 unlockedActiveBalance = _lastUnlockedActiveBalanceOf(juror); uint256 nextTermDeactivationRequestAmount = _deactivationRequestedAmountForTerm(juror, nextTermId); // Check if the juror has enough unlocked tokens to collect the requested amount // Note that we're also considering the deactivation request if there is any uint256 totalUnlockedActiveBalance = unlockedActiveBalance.add(nextTermDeactivationRequestAmount); if (_amount > totalUnlockedActiveBalance) { return false; } // Check if the amount of active tokens is enough to collect the requested amount, otherwise reduce the requested deactivation amount of // the next term. Note that this behaviour is different to the one when drafting jurors since this function is called as a side effect // of a juror deliberately voting in a final round, while drafts occur randomly. if (_amount > unlockedActiveBalance) { // No need for SafeMath: amounts were already checked above uint256 amountToReduce = _amount - unlockedActiveBalance; _reduceDeactivationRequest(_juror, amountToReduce, _termId); } _updateBrightIdActiveStake(_juror, _amount, false); tree.update(juror.id, nextTermId, _amount, false); emit JurorTokensCollected(_juror, _amount, nextTermId); return true; } /** * @notice Lock `_juror`'s withdrawals until term #`_termId` * @dev This is intended for jurors who voted in a final round and were coherent with the final ruling to prevent 51% attacks * @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 onlyDisputeManager { Juror storage juror = jurorsByAddress[_juror]; juror.withdrawalsLockTermId = _termId; } /** * @notice Set new limit of total active balance of juror tokens to `_totalActiveBalanceLimit` * @param _totalActiveBalanceLimit New limit of total active balance of juror tokens */ function setTotalActiveBalanceLimit(uint256 _totalActiveBalanceLimit) external onlyConfigGovernor { _setTotalActiveBalanceLimit(_totalActiveBalanceLimit); } /** * @dev ERC900 - Tell the address of the token used for staking * @return Address of the token used for staking */ function token() external view returns (address) { return address(jurorsToken); } /** * @dev ERC900 - Tell the total amount of juror tokens held by the registry contract * @return Amount of juror tokens held by the registry contract */ function totalStaked() external view returns (uint256) { return jurorsToken.balanceOf(address(this)); } /** * @dev Tell the total amount of active juror tokens * @return Total amount of active juror tokens */ function totalActiveBalance() external view returns (uint256) { return tree.getTotal(); } /** * @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) { return _totalActiveBalanceAt(_termId); } /** * @dev ERC900 - Tell the total amount of tokens of juror. This includes the active balance, the available * balances, and the pending balance for deactivation. Note that we don't have to include the locked * balances since these represent the amount of active tokens that are locked for drafts, i.e. these * are included in the active balance of the juror. * @param _juror Address of the juror querying the total amount of tokens staked of * @return Total amount of tokens of a juror */ function totalStakedFor(address _juror) external view returns (uint256) { return _totalStakedFor(_juror); } /** * @dev Tell the balance information of a juror * @param _juror Address of the juror querying the balance information of * @return active Amount of active tokens of a juror * @return available Amount of available tokens of a juror * @return locked Amount of active tokens that are locked due to ongoing disputes * @return pendingDeactivation Amount of active tokens that were requested for deactivation */ function balanceOf(address _juror) external view returns (uint256 active, uint256 available, uint256 locked, uint256 pendingDeactivation) { return _balanceOf(_juror); } /** * @dev Tell the balance information of a juror, fecthing tree one at a given term * @param _juror Address of the juror querying the balance information of * @param _termId Term ID querying the active balance for * @return active Amount of active tokens of a juror * @return available Amount of available tokens of a juror * @return locked Amount of active tokens that are locked due to ongoing disputes * @return pendingDeactivation Amount of active tokens that were requested for deactivation */ function balanceOfAt(address _juror, uint64 _termId) external view returns (uint256 active, uint256 available, uint256 locked, uint256 pendingDeactivation) { Juror storage juror = jurorsByAddress[_juror]; active = _existsJuror(juror) ? tree.getItemAt(juror.id, _termId) : 0; (available, locked, pendingDeactivation) = _getBalances(juror); } /** * @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) { return _activeBalanceOfAt(_juror, _termId); } /** * @dev Tell the amount of active tokens of a juror at the last ensured term that are not locked due to ongoing disputes * @param _juror Address of the juror querying the unlocked balance of * @return Amount of active tokens of a juror that are not locked due to ongoing disputes */ function unlockedActiveBalanceOf(address _juror) external view returns (uint256) { Juror storage juror = jurorsByAddress[_juror]; return _currentUnlockedActiveBalanceOf(juror); } /** * @dev Tell the total amount of active tokens for the jurors BrightId account * @param _juror Any of the BrightId accounts registered juror addresses * @return Amount of active tokens of a juror */ function jurorsTotalActiveStake(address _juror) external view returns (uint256) { if (_brightIdRegister().hasUniqueUserId(_juror)) { address jurorBrightId = _jurorBrightId(_juror); return brightIdActiveStake[jurorBrightId]; } else { return 0; } } /** * @dev Tell the max balance a juror can currently activate, calculated using a sliding scale of a percent of the total supply * @param _termId The term to use the config from, note the output changes dependant on the juror tokens total supply * @return Max amount of tokens a juror can activate at this time */ function maxActiveBalance(uint64 _termId) public view returns (uint256) { IClock clock = _clock(); uint256 celesteTokenTotalSupply = clock.getTermTokenTotalSupply(_termId); if (celesteTokenTotalSupply == 0) { return 0; } uint256 minMaxPctTotalSupply = _getConfigAt(_termId).jurors.minMaxPctTotalSupply; uint256 maxMaxPctTotalSupply = _getConfigAt(_termId).jurors.maxMaxPctTotalSupply; uint256 diffOfPct = maxMaxPctTotalSupply - minMaxPctTotalSupply; // No need for safemath, we ensure min is less than max in config setting uint256 totalActiveBalanceAtTerm = _totalActiveBalanceAt(_termId); uint256 currentPctOfTotalSupply = maxMaxPctTotalSupply.sub(totalActiveBalanceAtTerm.mul(diffOfPct) / celesteTokenTotalSupply); uint256 maxActiveBalance = celesteTokenTotalSupply.pctHighPrecision(currentPctOfTotalSupply); // Due to fluctuations in the celeste token's total supply we can't ensure min active balance is less than // the max active balance because max active balance is determined using the celeste token's total supply. // Therefore set max active balance to min active balance if it less then min active balance. uint256 minActiveBalance = _getMinActiveBalance(_termId + 1); if (maxActiveBalance < minActiveBalance) { maxActiveBalance = minActiveBalance; } return maxActiveBalance; } /** * @dev Tell the pending deactivation details for a juror * @param _juror Address of the juror whose info is requested * @return amount Amount to be deactivated * @return availableTermId Term in which the deactivated amount will be available */ function getDeactivationRequest(address _juror) external view returns (uint256 amount, uint64 availableTermId) { DeactivationRequest storage request = jurorsByAddress[_juror].deactivationRequest; return (request.amount, request.availableTermId); } /** * @dev Tell the withdrawals lock term ID for a juror * @param _juror Address of the juror whose info is requested * @return Term ID until which the juror's withdrawals will be locked */ function getWithdrawalsLockTermId(address _juror) external view returns (uint64) { return jurorsByAddress[_juror].withdrawalsLockTermId; } /** * @dev Tell the identification number associated to a juror address * @param _juror Address of the juror querying the identification number of * @return Identification number associated to a juror address, zero in case it wasn't registered yet */ function getJurorId(address _juror) external view returns (uint256) { return jurorsByAddress[_juror].id; } /** * @dev Tell the maximum amount of total active balance that can be held in the registry * @return Maximum amount of total active balance that can be held in the registry */ function totalJurorsActiveBalanceLimit() external view returns (uint256) { return totalActiveBalanceLimit; } /** * @dev ERC900 - Tell if the current registry supports historic information or not * @return Always false */ function supportsHistory() external pure returns (bool) { return false; } /** * @dev Internal function to activate a given amount of tokens for a juror. * This function assumes that the given term is the current term and has already been ensured. * @param _juror Address of the juror to activate tokens * @param _amount Amount of juror tokens to be activated * @param _sender Address of the account requesting the activation */ function _activateTokens(address _juror, uint256 _amount, address _sender) internal { uint64 termId = _ensureCurrentTerm(); // Try to clean a previous deactivation request if any _processDeactivationRequest(_juror, termId); uint256 availableBalance = jurorsByAddress[_juror].availableBalance; uint256 amountToActivate = _amount == 0 ? availableBalance : _amount; require(amountToActivate > 0, ERROR_INVALID_ZERO_AMOUNT); require(amountToActivate <= availableBalance, ERROR_INVALID_ACTIVATION_AMOUNT); uint64 nextTermId = termId + 1; _checkTotalActiveBalance(nextTermId, amountToActivate); Juror storage juror = jurorsByAddress[_juror]; uint256 minActiveBalance = _getMinActiveBalance(nextTermId); uint256 maxActiveBalance = maxActiveBalance(termId); if (_existsJuror(juror)) { // Even though we are adding amounts, let's check the new active balance is greater than or equal to the // minimum active amount. Note that the juror might have been slashed. uint256 activeBalance = tree.getItem(juror.id); uint256 newActiveBalance = activeBalance.add(amountToActivate); require(newActiveBalance >= minActiveBalance, ERROR_ACTIVE_BALANCE_BELOW_MIN); tree.update(juror.id, nextTermId, amountToActivate, true); } else { require(amountToActivate >= minActiveBalance, ERROR_ACTIVE_BALANCE_BELOW_MIN); juror.id = tree.insert(nextTermId, amountToActivate); jurorsAddressById[juror.id] = _juror; } uint256 jurorsNewTotalActiveStake = _updateBrightIdActiveStake(_juror, amountToActivate, true); require(jurorsNewTotalActiveStake <= maxActiveBalance, ERROR_ACTIVE_BALANCE_ABOVE_MAX); _updateAvailableBalanceOf(_juror, amountToActivate, false); emit JurorActivated(_juror, nextTermId, amountToActivate, _sender); } /** * @dev Internal function to create a token deactivation request for a juror. Jurors will be allowed * to process a deactivation request from the next term. * @param _juror Address of the juror to create a token deactivation request for * @param _amount Amount of juror tokens requested for deactivation */ function _createDeactivationRequest(address _juror, uint256 _amount) internal { uint64 termId = _ensureCurrentTerm(); // Try to clean a previous deactivation request if possible _processDeactivationRequest(_juror, termId); uint64 nextTermId = termId + 1; Juror storage juror = jurorsByAddress[_juror]; DeactivationRequest storage request = juror.deactivationRequest; request.amount = request.amount.add(_amount); request.availableTermId = nextTermId; _updateBrightIdActiveStake(_juror, _amount, false); tree.update(juror.id, nextTermId, _amount, false); emit JurorDeactivationRequested(_juror, nextTermId, _amount); } /** * @dev Internal function to process a token deactivation requested by a juror. It will move the requested amount * to the available balance of the juror if the term when the deactivation was requested has already finished. * @param _juror Address of the juror to process the deactivation request of * @param _termId Current term id */ function _processDeactivationRequest(address _juror, uint64 _termId) internal { Juror storage juror = jurorsByAddress[_juror]; DeactivationRequest storage request = juror.deactivationRequest; uint64 deactivationAvailableTermId = request.availableTermId; // If there is a deactivation request, ensure that the deactivation term has been reached if (deactivationAvailableTermId == uint64(0) || _termId < deactivationAvailableTermId) { return; } uint256 deactivationAmount = request.amount; // Note that we can use a zeroed term ID to denote void here since we are storing // the minimum allowed term to deactivate tokens which will always be at least 1. request.availableTermId = uint64(0); request.amount = 0; _updateAvailableBalanceOf(_juror, deactivationAmount, true); emit JurorDeactivationProcessed(_juror, deactivationAvailableTermId, deactivationAmount, _termId); } /** * @dev Internal function to reduce a token deactivation requested by a juror. It assumes the deactivation request * cannot be processed for the given term yet. * @param _juror Address of the juror to reduce the deactivation request of * @param _amount Amount to be reduced from the current deactivation request * @param _termId Term ID in which the deactivation request is being reduced */ function _reduceDeactivationRequest(address _juror, uint256 _amount, uint64 _termId) internal { Juror storage juror = jurorsByAddress[_juror]; DeactivationRequest storage request = juror.deactivationRequest; uint256 currentRequestAmount = request.amount; require(currentRequestAmount >= _amount, ERROR_CANNOT_REDUCE_DEACTIVATION_REQUEST); // No need for SafeMath: we already checked values above uint256 newRequestAmount = currentRequestAmount - _amount; request.amount = newRequestAmount; _updateBrightIdActiveStake(_juror, _amount, true); // Move amount back to the tree tree.update(juror.id, _termId + 1, _amount, true); emit JurorDeactivationUpdated(_juror, request.availableTermId, newRequestAmount, _termId); } /** * @dev Internal function to stake an amount of tokens for a juror * @param _from Address sending the amount of tokens to be deposited * @param _juror Address of the juror to deposit the tokens to * @param _amount Amount of tokens to be deposited * @param _data Optional data that can be used to request the activation of the deposited tokens */ function _stake(address _from, address _juror, uint256 _amount, bytes memory _data) internal { require(_amount > 0, ERROR_INVALID_ZERO_AMOUNT); _updateAvailableBalanceOf(_juror, _amount, true); // Activate tokens if it was requested by the sender. Note that there's no need to check // the activation amount since we have just added it to the available balance of the juror. if (_data.toBytes4() == JurorsRegistry(this).activate.selector) { _activateTokens(_juror, _amount, _from); } emit Staked(_juror, _amount, _totalStakedFor(_juror), _data); require(jurorsToken.safeTransferFrom(_from, address(this), _amount), ERROR_TOKEN_TRANSFER_FAILED); } /** * @dev Internal function to unstake an amount of tokens of a juror * @param _juror Address of the juror to to unstake the tokens of * @param _amount Amount of tokens to be unstaked * @param _data Optional data is never used by this function, only logged */ function _unstake(address _juror, uint256 _amount, bytes memory _data) internal { require(_amount > 0, ERROR_INVALID_ZERO_AMOUNT); // Try to process a deactivation request for the current term if there is one. Note that we don't need to ensure // the current term this time since deactivation requests always work with future terms, which means that if // the current term is outdated, it will never match the deactivation term id. We avoid ensuring the term here // to avoid forcing jurors to do that in order to withdraw their available balance. Same applies to final round locks. uint64 lastEnsuredTermId = _getLastEnsuredTermId(); // Check that juror's withdrawals are not locked uint64 withdrawalsLockTermId = jurorsByAddress[_juror].withdrawalsLockTermId; require(withdrawalsLockTermId == 0 || withdrawalsLockTermId < lastEnsuredTermId, ERROR_WITHDRAWALS_LOCK); _processDeactivationRequest(_juror, lastEnsuredTermId); _updateAvailableBalanceOf(_juror, _amount, false); emit Unstaked(_juror, _amount, _totalStakedFor(_juror), _data); require(jurorsToken.safeTransfer(_juror, _amount), ERROR_TOKEN_TRANSFER_FAILED); } /** * @dev Internal function to update the available balance of a juror * @param _juror Juror to update the available balance of * @param _amount Amount of tokens to be added to or removed from the available balance of a juror * @param _positive True if the given amount should be added, or false to remove it from the available balance */ function _updateAvailableBalanceOf(address _juror, uint256 _amount, bool _positive) internal { // We are not using a require here to avoid reverting in case any of the treasury maths reaches this point // with a zeroed amount value. Instead, we are doing this validation in the external entry points such as // stake, unstake, activate, deactivate, among others. if (_amount == 0) { return; } Juror storage juror = jurorsByAddress[_juror]; if (_positive) { juror.availableBalance = juror.availableBalance.add(_amount); } else { require(_amount <= juror.availableBalance, ERROR_NOT_ENOUGH_AVAILABLE_BALANCE); // No need for SafeMath: we already checked values right above juror.availableBalance -= _amount; } } /** * @dev Internal function to set new limit of total active balance of juror tokens * @param _totalActiveBalanceLimit New limit of total active balance of juror tokens */ function _setTotalActiveBalanceLimit(uint256 _totalActiveBalanceLimit) internal { require(_totalActiveBalanceLimit > 0, ERROR_BAD_TOTAL_ACTIVE_BALANCE_LIMIT); require(_totalActiveBalanceLimit > maxActiveBalance(_getLastEnsuredTermId()), ERROR_TOTAL_ACTIVE_BALANCE_TOO_LOW); emit TotalActiveBalanceLimitChanged(totalActiveBalanceLimit, _totalActiveBalanceLimit); totalActiveBalanceLimit = _totalActiveBalanceLimit; } /** * @dev Internal function to tell the total amount of tokens of juror * @param _juror Address of the juror querying the total amount of tokens staked of * @return Total amount of tokens of a juror */ function _totalStakedFor(address _juror) internal view returns (uint256) { (uint256 active, uint256 available, , uint256 pendingDeactivation) = _balanceOf(_juror); return available.add(active).add(pendingDeactivation); } /** * @dev Internal function to tell the balance information of a juror * @param _juror Address of the juror querying the balance information of * @return active Amount of active tokens of a juror * @return available Amount of available tokens of a juror * @return locked Amount of active tokens that are locked due to ongoing disputes * @return pendingDeactivation Amount of active tokens that were requested for deactivation */ function _balanceOf(address _juror) internal view returns (uint256 active, uint256 available, uint256 locked, uint256 pendingDeactivation) { Juror storage juror = jurorsByAddress[_juror]; active = _existsJuror(juror) ? tree.getItem(juror.id) : 0; (available, locked, pendingDeactivation) = _getBalances(juror); } /** * @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) internal view returns (uint256) { Juror storage juror = jurorsByAddress[_juror]; return _existsJuror(juror) ? tree.getItemAt(juror.id, _termId) : 0; } /** * @dev Internal function to get the amount of active tokens of a juror that are not locked due to ongoing disputes * It will use the last value, that might be in a future term * @param _juror Juror querying the unlocked active balance of * @return Amount of active tokens of a juror that are not locked due to ongoing disputes */ function _lastUnlockedActiveBalanceOf(Juror storage _juror) internal view returns (uint256) { return _existsJuror(_juror) ? tree.getItem(_juror.id).sub(_juror.lockedBalance) : 0; } /** * @dev Internal function to get the amount of active tokens at the last ensured term of a juror that are not locked due to ongoing disputes * @param _juror Juror querying the unlocked active balance of * @return Amount of active tokens of a juror that are not locked due to ongoing disputes */ function _currentUnlockedActiveBalanceOf(Juror storage _juror) internal view returns (uint256) { uint64 lastEnsuredTermId = _getLastEnsuredTermId(); return _existsJuror(_juror) ? tree.getItemAt(_juror.id, lastEnsuredTermId).sub(_juror.lockedBalance) : 0; } /** * @dev Internal function to check if a juror was already registered * @param _juror Juror to be checked * @return True if the given juror was already registered, false otherwise */ function _existsJuror(Juror storage _juror) internal view returns (bool) { return _juror.id != 0; } /** * @dev Internal function to get the amount of a deactivation request for a given term id * @param _juror Juror to query the deactivation request amount of * @param _termId Term ID of the deactivation request to be queried * @return Amount of the deactivation request for the given term, 0 otherwise */ function _deactivationRequestedAmountForTerm(Juror storage _juror, uint64 _termId) internal view returns (uint256) { DeactivationRequest storage request = _juror.deactivationRequest; return request.availableTermId == _termId ? request.amount : 0; } /** * @dev Internal function to 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) internal view returns (uint256) { // This function will return always the same values, the only difference remains on gas costs. In case we look for a // recent term, in this case current or future ones, we perform a backwards linear search from the last checkpoint. // Otherwise, a binary search is computed. bool recent = _termId >= _getLastEnsuredTermId(); return recent ? tree.getRecentTotalAt(_termId) : tree.getTotalAt(_termId); } /** * @dev Internal function to check if its possible to add a given new amount to the registry or not * @param _termId Term ID when the new amount will be added * @param _amount Amount of tokens willing to be added to the registry */ function _checkTotalActiveBalance(uint64 _termId, uint256 _amount) internal view { uint256 currentTotalActiveBalance = _totalActiveBalanceAt(_termId); uint256 newTotalActiveBalance = currentTotalActiveBalance.add(_amount); require(newTotalActiveBalance <= totalActiveBalanceLimit, ERROR_TOTAL_ACTIVE_BALANCE_EXCEEDED); } /** * @dev Tell the local balance information of a juror (that is not on the tree) * @param _juror Address of the juror querying the balance information of * @return available Amount of available tokens of a juror * @return locked Amount of active tokens that are locked due to ongoing disputes * @return pendingDeactivation Amount of active tokens that were requested for deactivation */ function _getBalances(Juror storage _juror) internal view returns (uint256 available, uint256 locked, uint256 pendingDeactivation) { available = _juror.availableBalance; locked = _juror.lockedBalance; pendingDeactivation = _juror.deactivationRequest.amount; } /** * @dev Internal function to search jurors in the tree based on certain search restrictions * @param _params Draft params to be used for the jurors search * @return ids List of juror ids obtained based on the requested search * @return activeBalances List of active balances for each juror obtained based on the requested search */ function _treeSearch(DraftParams memory _params) internal view returns (uint256[] memory ids, uint256[] memory activeBalances) { (ids, activeBalances) = tree.batchedRandomSearch( _params.termRandomness, _params.disputeId, _params.termId, _params.selectedJurors, _params.batchRequestedJurors, _params.roundRequestedJurors, _params.iteration ); } /** * @dev Private function to parse a certain set given of draft params * @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 Draft params object parsed */ function _buildDraftParams(uint256[7] memory _params) private view returns (DraftParams memory) { uint64 termId = uint64(_params[2]); uint256 minActiveBalance = _getMinActiveBalance(termId); return DraftParams({ termRandomness: bytes32(_params[0]), disputeId: _params[1], termId: termId, selectedJurors: _params[3], batchRequestedJurors: _params[4], roundRequestedJurors: _params[5], draftLockAmount: minActiveBalance.pct(uint16(_params[6])), iteration: 0 }); } /** * @dev Function to convert a jurors sender address to their unique BrightId address */ function _jurorBrightId(address _jurorSenderAddress) internal view returns (address) { return _brightIdRegister().uniqueUserId(_jurorSenderAddress); } /** * @dev Function to update the total active stake of the jurors BrightId account */ function _updateBrightIdActiveStake(address _juror, uint256 _amount, bool _increase) internal returns (uint256) { address jurorBrightId = _jurorBrightId(_juror); uint256 brightIdUserCurrentActiveStake = brightIdActiveStake[jurorBrightId]; if (_increase) { brightIdActiveStake[jurorBrightId] = brightIdUserCurrentActiveStake.add(_amount); } else { brightIdActiveStake[jurorBrightId] = brightIdUserCurrentActiveStake.sub(_amount); } return brightIdActiveStake[jurorBrightId]; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[{"name":"_juror","type":"address"},{"name":"_termId","type":"uint64"}],"name":"balanceOfAt","outputs":[{"name":"active","type":"uint256"},{"name":"available","type":"uint256"},{"name":"locked","type":"uint256"},{"name":"pendingDeactivation","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"stake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"stakeFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_juror","type":"address"}],"name":"jurorsTotalActiveStake","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_to","type":"address"}],"name":"recoverFunds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getController","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_juror","type":"address"}],"name":"totalStakedFor","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_juror","type":"address"},{"name":"_amount","type":"uint256"}],"name":"assignTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_juror","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_termId","type":"uint64"}],"name":"collectTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_termId","type":"uint64"}],"name":"maxActiveBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"burnTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_juror","type":"address"}],"name":"getDeactivationRequest","outputs":[{"name":"amount","type":"uint256"},{"name":"availableTermId","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"supportsHistory","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"_juror","type":"address"}],"name":"balanceOf","outputs":[{"name":"active","type":"uint256"},{"name":"available","type":"uint256"},{"name":"locked","type":"uint256"},{"name":"pendingDeactivation","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalStaked","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_jurorSenderAddress","type":"address"},{"name":"_jurorUniqueId","type":"address"},{"name":"_data","type":"bytes"}],"name":"receiveRegistration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_termId","type":"uint64"}],"name":"totalActiveBalanceAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_token","type":"address"},{"name":"_data","type":"bytes"}],"name":"receiveApproval","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"deactivate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_juror","type":"address"}],"name":"unlockedActiveBalanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_juror","type":"address"}],"name":"processDeactivationRequest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_juror","type":"address"}],"name":"getWithdrawalsLockTermId","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_juror","type":"address"},{"name":"_termId","type":"uint64"}],"name":"lockWithdrawals","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"activate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_termId","type":"uint64"},{"name":"_jurors","type":"address[]"},{"name":"_lockedAmounts","type":"uint256[]"},{"name":"_rewardedJurors","type":"bool[]"}],"name":"slashOrUnlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"unstake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_params","type":"uint256[7]"}],"name":"draft","outputs":[{"name":"jurors","type":"address[]"},{"name":"length","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalJurorsActiveBalanceLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_totalActiveBalanceLimit","type":"uint256"}],"name":"setTotalActiveBalanceLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_juror","type":"address"},{"name":"_termId","type":"uint64"}],"name":"activeBalanceOfAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_juror","type":"address"}],"name":"getJurorId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalActiveBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_controller","type":"address"},{"name":"_totalActiveBalanceLimit","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"juror","type":"address"},{"indexed":false,"name":"fromTermId","type":"uint64"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"sender","type":"address"}],"name":"JurorActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"juror","type":"address"},{"indexed":false,"name":"availableTermId","type":"uint64"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"JurorDeactivationRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"juror","type":"address"},{"indexed":false,"name":"availableTermId","type":"uint64"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"processedTermId","type":"uint64"}],"name":"JurorDeactivationProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"juror","type":"address"},{"indexed":false,"name":"availableTermId","type":"uint64"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"updateTermId","type":"uint64"}],"name":"JurorDeactivationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"juror","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"JurorBalanceLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"juror","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"JurorBalanceUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"juror","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"effectiveTermId","type":"uint64"}],"name":"JurorSlashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"juror","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"JurorTokensAssigned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"JurorTokensBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"juror","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"effectiveTermId","type":"uint64"}],"name":"JurorTokensCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"previousTotalActiveBalanceLimit","type":"uint256"},{"indexed":false,"name":"currentTotalActiveBalanceLimit","type":"uint256"}],"name":"TotalActiveBalanceLimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"total","type":"uint256"},{"indexed":false,"name":"data","type":"bytes"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"total","type":"uint256"},{"indexed":false,"name":"data","type":"bytes"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"recipient","type":"address"},{"indexed":false,"name":"balance","type":"uint256"}],"name":"RecoverFunds","type":"event"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051604080620069f5833981018060405260408110156200003357600080fd5b50805160209182015190918290819062000053908290620001dc811b901c565b6040518060400160405280601b81526020017f4354445f434f4e54524f4c4c45525f4e4f545f434f4e545241435400000000008152509062000130576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620000f4578181015183820152602001620000da565b50505050905090810190601f168015620001225780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600080546001600160a01b0319166001600160a01b039290921691909117815562000164915062000201602090811b901c565b5151600280546001600160a01b0319166001600160a01b03909216919091179055620001978162000547602090811b901c565b620001ae6005620006e960201b620052361760201c565b620001cc60008060056200071260201b620041dc179092919060201c565b15620001d457fe5b505062001766565b60006001600160a01b038216620001f657506000620001fc565b50803b15155b919050565b6200020b620015e4565b6000620002176200161d565b6000620002236200163b565b6200022d6200165a565b620002376200165a565b6200024162001678565b620002516200076c60201b60201c565b6001600160a01b031663e008cb628a6040518263ffffffff1660e01b815260040180826001600160401b03166001600160401b031681526020019150506102c06040518083038186803b158015620002a857600080fd5b505afa158015620002bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102c0811015620002e457600080fd5b5080516080820151909850602082019750955060a0810194506101c081019350610200810192506102400190506200031b620015e4565b6040805160a0810182526001600160a01b038a16815260208681015161ffff168183015289518284015289810151606083015289830151608083015290835281516101a08101835260ff8916815287516001600160401b03169181019190915290810186600160200201516001600160401b0316815260200186600260098110620003a257fe5b60200201516001600160401b0316815260200186600360098110620003c357fe5b60200201516001600160401b0316815260200186600460098110620003e457fe5b60200201516001600160401b03168152602001856000600281106200040557fe5b602002015161ffff168152602001866005600981106200042157fe5b60200201516001600160401b03168152602001866006600981106200044257fe5b60200201516001600160401b03168152602001866008600981106200046357fe5b60200201516001600160401b03168152602001866007600981106200048457fe5b60200201516001600160401b0316815260200184600060028110620004a557fe5b6020020151815260200184600160028110620004bd57fe5b60200201518152508160200181905250604051806080016040528083600060048110620004e657fe5b6020020151815260200183600160048110620004fe57fe5b60200201518152602001836002600481106200051657fe5b60200201518152602001836003600481106200052e57fe5b6020020151905260408201529998505050505050505050565b60408051808201909152601d81527f4a525f4241445f544f54414c5f4143544956455f42414c5f4c494d4954000000602082015281620005e4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000f4578181015183820152602001620000da565b5062000605620005f96200077b60201b60201c565b620007f960201b60201c565b81116040518060400160405280601f81526020017f4a525f544f54414c5f4143544956455f42414c414e43455f544f4f5f4c4f570081525090620006a6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000f4578181015183820152602001620000da565b50600154604080519182526020820183905280517f9ce60e2304bd08c7c9e6da0e10912e44f85fd9e2ee71c1842132f12146c586c89281900390910190a1600155565b6200070c600080600101836001016200099160201b620043cd179092919060201c565b60009055565b82546001810184556000906200073185828662000a51602090811b901c565b821562000764576200074e85600083878762000ad860201b60201c565b6200076485828686600162000b1260201b60201c565b949350505050565b6000546001600160a01b031690565b60006200078d6200076c60201b60201c565b6001600160a01b031663f7fe57896040518163ffffffff1660e01b815260040160206040518083038186803b158015620007c657600080fd5b505afa158015620007db573d6000803e3d6000fd5b505050506040513d6020811015620007f257600080fd5b5051905090565b6000806200080c6200076c60201b60201c565b90506000816001600160a01b03166382cf57ae856040518263ffffffff1660e01b815260040180826001600160401b03166001600160401b0316815260200191505060206040518083038186803b1580156200086757600080fd5b505afa1580156200087c573d6000803e3d6000fd5b505050506040513d60208110156200089357600080fd5b5051905080620008a957600092505050620001fc565b6000620008bc856200020160201b60201c565b604001516020015190506000620008d9866200020160201b60201c565b60400151604001519050600082820390506000620008fd8862000c8960201b60201c565b905060006200093e8662000920858562000cfc60201b62002ee21790919060201c565b816200092857fe5b048562000dc660201b62002f851790919060201c565b905060006200095c828862000e7260201b620030171790919060201c565b90506000620009748b60010162000ea760201b60201c565b90508082101562000983578091505b509998505050505050505050565b60408051808201909152601881527f434845434b504f494e545f56414c55455f544f4f5f424947000000000000000060208201526001600160c01b0382111562000a38576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000f4578181015183820152602001620000da565b5062000a4c83838362000f4360201b60201c565b505050565b600062000a6484620010f660201b60201c565b905062000a7881846200111160201b60201c565b1562000ad25760018101600062000a9886848362001141602090811b901c565b905062000ab086836000878562000ad860201b60201c565b62000acf8483886001016200099160201b620043cd179092919060201c565b50505b50505050565b60008481526002860160209081526040808320868452825290912062000b0b9184908490620043cd62000991821b17901c565b5050505050565b60001984600062000b2a88620010f6602090811b901c565b905060015b81811162000bbe57600484901b93508383169250600062000b588a83866200114160201b60201c565b905060008662000b825762000b7c888362000dc660201b62002f851790919060201c565b62000b9c565b62000b9c88836200116f60201b620028191790919060201c565b905062000bb38b84878c8562000ad860201b60201c565b505060010162000b2f565b5083158062000bdf57508462000bdc8983856200114160201b60201c565b10155b6040518060400160405280601881526020017f53554d5f545245455f5550444154455f4f564552464c4f5700000000000000008152509062000c7e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000f4578181015183820152602001620000da565b505050505050505050565b60008062000c9c6200077b60201b60201c565b6001600160401b0316836001600160401b0316101590508062000cda5762000cd48360056200121660201b620040f81790919060201c565b62000cf5565b62000cf58360056200124260201b620041141790919060201c565b9392505050565b60008262000d0d5750600062000dc0565b8282028284828162000d1b57fe5b04146040518060400160405280601181526020017f4d4154485f4d554c5f4f564552464c4f570000000000000000000000000000008152509062000dbc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000f4578181015183820152602001620000da565b5090505b92915050565b6000828211156040518060400160405280601281526020017f4d4154485f5355425f554e444552464c4f5700000000000000000000000000008152509062000e6b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000f4578181015183820152602001620000da565b5050900390565b6000670de0b6b3a764000062000e97838562000cfc60201b62002ee21790919060201c565b8162000e9f57fe5b049392505050565b600062000eb96200076c60201b60201c565b6001600160a01b03166395f3c2da836040518263ffffffff1660e01b815260040180826001600160401b03166001600160401b0316815260200191505060206040518083038186803b15801562000f0f57600080fd5b505afa15801562000f24573d6000803e3d6000fd5b505050506040513d602081101562000f3b57600080fd5b505192915050565b825480158062000f83575083546001600160401b038416908590600019810190811062000f6c57fe5b6000918252602090912001546001600160401b0316105b1562000ff957604080518082019091526001600160401b0380851682526001600160c01b0380851660208085019182528854600181018a5560008a815291909120945194018054915190921668010000000000000000029383166001600160401b03199091161790911691909117905562000ad2565b60008460000160018303815481106200100e57fe5b6000918252602091829020018054604080518082019091528381527f434845434b504f494e545f43414e4e4f545f4144445f504153545f56414c5545938101939093529092506001600160401b03868116911614620010ca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000f4578181015183820152602001620000da565b5080546001600160c01b03841668010000000000000000026001600160401b0390911617905550505050565b600062000dc0826001016200126e60201b6200497a1760201c565b6000806200112f60048562000cfc60201b62002ee21790919060201c565b600019901b8316151591505092915050565b600082815260028401602090815260408083208484528252822062000764916200497a6200126e821b17901c565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f570000000000000000000000000000006020820152600090838301908482101562000dbc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000f4578181015183820152602001620000da565b6000806200122b8484620012c160201b60201c565b9050620007648482600086620012e060201b60201c565b600080620012578484620012c160201b60201c565b90506200076484826000866200131960201b60201c565b80546000908015620012b8578260000160018203815481106200128d57fe5b6000918252602090912001546801000000000000000090046001600160c01b03169150620001fc9050565b50600092915050565b600062000cf582846001016200134960201b62004cdd1790919060201c565b600083815260028501602090815260408083208584528252822062001310918490620043c16200135d821b17901c565b95945050505050565b60008381526002850160209081526040808320858452825282206200131091849062004cdd62001349821b17901c565b600062000cf583836200137160201b60201c565b600062000cf583836200143660201b60201c565b8154600090806200138757600091505062000dc0565b83546000198201906000908690839081106200139f57fe5b9060005260206000200190505b600082118015620013c9575080546001600160401b038087169116115b15620013f757855460001990920191869083908110620013e557fe5b906000526020600020019050620013ac565b80546001600160401b03808716911611620014295780546801000000000000000090046001600160c01b03166200142c565b60005b9695505050505050565b8154600090806200144c57600091505062000dc0565b83546000198201908590829081106200146157fe5b6000918252602090912001546001600160401b0390811690851610620014bd578460000181815481106200149157fe5b6000918252602090912001546801000000000000000090046001600160c01b0316925062000dc0915050565b84600001600081548110620014ce57fe5b6000918252602090912001546001600160401b039081169085161015620014fb5760009250505062000dc0565b6000815b81811115620015a8578654600283830160010104906000908990839081106200152457fe5b600091825260209091200180549091506001600160401b0390811690891681101562001553578294506200159f565b806001600160401b0316896001600160401b031610156200157a576001830393506200159f565b50546801000000000000000090046001600160c01b0316955062000dc0945050505050565b505050620014ff565b866000018281548110620015b857fe5b6000918252602090912001546801000000000000000090046001600160c01b0316979650505050505050565b604051806102c00160405280620015fa62001696565b815260200162001609620016d2565b8152602001620016186200173e565b905290565b60405180606001604052806003906020820280388339509192915050565b6040518061012001604052806009906020820280388339509192915050565b60405180604001604052806002906020820280388339509192915050565b60405180608001604052806004906020820280388339509192915050565b6040518060a0016040528060006001600160a01b03168152602001600061ffff1681526020016000815260200160008152602001600081525090565b604080516101a081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081019190915290565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b61527f80620017766000396000f3fe608060405234801561001057600080fd5b50600436106101fb5760003560e01c80638e1277931161011a578063c67106f5116100ad578063e67a81f41161007c578063e67a81f414610989578063e9e67d67146109a6578063f01e7d03146109db578063f590e92314610a01578063fc0c546a14610a09576101fb565b8063c67106f514610777578063c8fd6ed014610895578063d903bcf41461090a578063dbbd85a614610981576101fb565b8063ac8fcfc0116100e9578063ac8fcfc0146106bd578063af7a9f40146106e3578063af8b9d0f14610725578063b260c42a1461075a576101fb565b80638e127793146105c75780638f4ffcb1146105ed578063916b9bef1461067a57806396a705c114610697576101fb565b8063605da1b2116101925780637033e4a6116101615780637033e4a61461050a57806370a0823114610512578063817b1cd214610538578063870e73c214610540576101fb565b8063605da1b21461043157806363d66609146104805780636d1b229d146104a65780636d6cc684146104c3576101fb565b806324ae6a27116101ce57806324ae6a271461038d5780633018205f146103bb5780634b341aed146103df5780634d7edc1514610405576101fb565b8063082b4235146102005780630e89439b1461025b5780630ef96356146102d25780631ae1c42714610355575b600080fd5b6102356004803603604081101561021657600080fd5b5080356001600160a01b031690602001356001600160401b0316610a11565b604080519485526020850193909352838301919091526060830152519081900360800190f35b6102d06004803603604081101561027157600080fd5b81359190810190604081016020820135600160201b81111561029257600080fd5b8201836020820111156102a457600080fd5b803590602001918460018302840111600160201b831117156102c557600080fd5b509092509050610a71565b005b6102d0600480360360608110156102e857600080fd5b6001600160a01b0382351691602081013591810190606081016040820135600160201b81111561031757600080fd5b82018360208201111561032957600080fd5b803590602001918460018302840111600160201b8311171561034a57600080fd5b509092509050610ab8565b61037b6004803603602081101561036b57600080fd5b50356001600160a01b0316610b00565b60408051918252519081900360200190f35b6102d0600480360360408110156103a357600080fd5b506001600160a01b0381358116916020013516610bc5565b6103c3610ef9565b604080516001600160a01b039092168252519081900360200190f35b61037b600480360360208110156103f557600080fd5b50356001600160a01b0316610f08565b6102d06004803603604081101561041b57600080fd5b506001600160a01b038135169060200135610f19565b61046c6004803603606081101561044757600080fd5b5080356001600160a01b031690602081013590604001356001600160401b0316611011565b604080519115158252519081900360200190f35b61037b6004803603602081101561049657600080fd5b50356001600160401b03166111bb565b6102d0600480360360208110156104bc57600080fd5b5035611304565b6104e9600480360360208110156104d957600080fd5b50356001600160a01b03166113f1565b604080519283526001600160401b0390911660208301528051918290030190f35b61046c611422565b6102356004803603602081101561052857600080fd5b50356001600160a01b0316611427565b61037b611445565b6102d06004803603606081101561055657600080fd5b6001600160a01b038235811692602081013590911691810190606081016040820135600160201b81111561058957600080fd5b82018360208201111561059b57600080fd5b803590602001918460018302840111600160201b831117156105bc57600080fd5b5090925090506114c4565b61037b600480360360208110156105dd57600080fd5b50356001600160401b031661173b565b6102d06004803603608081101561060357600080fd5b6001600160a01b038235811692602081013592604082013590921691810190608081016060820135600160201b81111561063c57600080fd5b82018360208201111561064e57600080fd5b803590602001918460018302840111600160201b8311171561066f57600080fd5b509092509050611746565b6102d06004803603602081101561069057600080fd5b503561183a565b61037b600480360360208110156106ad57600080fd5b50356001600160a01b0316611a3a565b6102d0600480360360208110156106d357600080fd5b50356001600160a01b0316611a5b565b610709600480360360208110156106f957600080fd5b50356001600160a01b0316611a71565b604080516001600160401b039092168252519081900360200190f35b6102d06004803603604081101561073b57600080fd5b5080356001600160a01b031690602001356001600160401b0316611a99565b6102d06004803603602081101561077057600080fd5b5035611b79565b61037b6004803603608081101561078d57600080fd5b6001600160401b038235169190810190604081016020820135600160201b8111156107b757600080fd5b8201836020820111156107c957600080fd5b803590602001918460208302840111600160201b831117156107ea57600080fd5b919390929091602081019035600160201b81111561080757600080fd5b82018360208201111561081957600080fd5b803590602001918460208302840111600160201b8311171561083a57600080fd5b919390929091602081019035600160201b81111561085757600080fd5b82018360208201111561086957600080fd5b803590602001918460208302840111600160201b8311171561088a57600080fd5b509092509050611b84565b6102d0600480360360408110156108ab57600080fd5b81359190810190604081016020820135600160201b8111156108cc57600080fd5b8201836020820111156108de57600080fd5b803590602001918460018302840111600160201b831117156108ff57600080fd5b509092509050611e8e565b610926600480360360e081101561092057600080fd5b50611ecf565b6040518080602001838152602001828103825284818151815260200191508051906020019060200280838360005b8381101561096c578181015183820152602001610954565b50505050905001935050505060405180910390f35b61037b6121a2565b6102d06004803603602081101561099f57600080fd5b50356121a8565b61037b600480360360408110156109bc57600080fd5b5080356001600160a01b031690602001356001600160401b0316612253565b61037b600480360360208110156109f157600080fd5b50356001600160a01b031661225f565b61037b61227a565b6103c361228b565b6001600160a01b0382166000908152600360205260408120819081908190610a388161229a565b610a43576000610a58565b8054610a58906005908863ffffffff6122a016565b9450610a63816122b7565b969991985096509350505050565b610ab333338585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506122cb92505050565b505050565b610afa33858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506122cb92505050565b50505050565b6000610b0a6124e8565b6001600160a01b03166351e11fd5836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610b5f57600080fd5b505afa158015610b73573d6000803e3d6000fd5b505050506040513d6020811015610b8957600080fd5b505115610bbc576000610b9b83612537565b6001600160a01b03166000908152600860205260409020549150610bc09050565b5060005b919050565b6000809054906101000a90046001600160a01b03166001600160a01b0316633c28e88b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c1257600080fd5b505afa158015610c26573d6000803e3d6000fd5b505050506040513d6020811015610c3c57600080fd5b505160408051808201909152601d81527f4354445f53454e4445525f4e4f545f46554e44535f474f5645524e4f520000006020820152906001600160a01b03163314610d0957604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610cce578181015183820152602001610cb6565b50505050905090810190601f168015610cfb5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060408051600160e01b6370a0823102815230600482015290516000916001600160a01b038516916370a0823191602480820192602092909190829003018186803b158015610d5757600080fd5b505afa158015610d6b573d6000803e3d6000fd5b505050506040513d6020811015610d8157600080fd5b505160408051808201909152601e81527f4354445f494e53554646494349454e545f5245434f5645525f46554e44530000602082015290915081610e0957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50610e246001600160a01b038416838363ffffffff6125c816565b6040518060400160405280601e81526020017f4354445f5245434f5645525f544f4b454e5f46554e44535f4641494c4544000081525090610ea957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50604080516001600160a01b0380861682528416602082015280820183905290517f724139fea3954691c2c1ee02b3be6be1763b32ec84841f1acad6d3a18695ba0d9181900360600190a1505050565b6000546001600160a01b031690565b6000610f138261263e565b92915050565b610f21612677565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090610fba57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50801561100d57610fcd828260016126c6565b6040805182815290516001600160a01b038416917fbfbd6786419e534c0af90164d33c027ddc81c4541f1047d00bb286d5d4dfe8a7919081900360200190a25b5050565b600061101b612677565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c450000815250906110b457604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50826110c2575060016111b4565b6001600160a01b038416600090815260036020526040812060018401916110e8826127ab565b905060006110f683856127eb565b9050600061110a838363ffffffff61281916565b905080881115611122576000955050505050506111b4565b8288111561113a578288036111388a828a6128ae565b505b611146898960006129ef565b50835461115f90600590878b600063ffffffff612a9616565b604080518981526001600160401b038716602082015281516001600160a01b038c16927f3b522789764bf3f50da1a4e79a6b330fd1ae121df88d89259fa73b55e1e9e360928290030190a26001955050505050505b9392505050565b6000806111c6610ef9565b90506000816001600160a01b03166382cf57ae856040518263ffffffff1660e01b815260040180826001600160401b03166001600160401b0316815260200191505060206040518083038186803b15801561122057600080fd5b505afa158015611234573d6000803e3d6000fd5b505050506040513d602081101561124a57600080fd5b505190508061125e57600092505050610bc0565b600061126985612b75565b60400151602001519050600061127e86612b75565b60409081015101519050818103600061129688612e94565b905060006112c4866112ae848663ffffffff612ee216565b816112b557fe5b8691900463ffffffff612f8516565b905060006112d8878363ffffffff61301716565b905060006112e88b600101613041565b9050808210156112f6578091505b509998505050505050505050565b61130c612677565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c450000815250906113a557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5080156113ee576113ba61dead8260016126c6565b6040805182815290517fef08526ce447c7a59448d28b89b25b9be13b2ae0293946c9cf27123c8e71a3769181900360200190a15b50565b6001600160a01b038116600090815260036020526040902060048101546005909101546001600160401b0316915091565b600090565b600080600080611436856130a0565b93509350935093509193509193565b60025460408051600160e01b6370a0823102815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561149357600080fd5b505afa1580156114a7573d6000803e3d6000fd5b505050506040513d60208110156114bd57600080fd5b5051905090565b6114cc6124e8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601f81526020017f4a525f53454e4445525f4e4f545f42524947485449445f5245474953544552008152509061156557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5060006115a783838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506130ff92505050565b905060006115f5600485858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff61311b169050565b90506001600160e01b03198216600160e11b63593062150214156116235761161e86828861313a565b611733565b6001600160e01b031982167f0e89439b0000000000000000000000000000000000000000000000000000000014156116b85760606116a46064600487878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092949392505063ffffffff61358b169050565b90506116b2878884846122cb565b50611733565b604080518082018252601481527f4a525f4e4f5f46554e4354494f4e5f4d4154434800000000000000000000000060208083019182529251600160e51b62461bcd0281526004810193845282516024820152825192939283926044909201919080838360008315610cce578181015183820152602001610cb6565b505050505050565b6000610f1382612e94565b336001600160a01b03841614801561176b57506002546001600160a01b038481169116145b6040518060400160405280601c81526020017f4a525f544f4b454e5f415050524f56455f4e4f545f414c4c4f57454400000000815250906117f057604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5061183385868685858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506122cb92505050565b5050505050565b600061184461364e565b33600090815260036020526040812091925061185f826127ab565b90506000841561186f5784611871565b815b9050600081116040518060400160405280601681526020017f4a525f494e56414c49445f5a45524f5f414d4f554e5400000000000000000000815250906118fc57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5060408051808201909152601e81527f4a525f494e56414c49445f444541435449564154494f4e5f414d4f554e54000060208201528282111561198357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50808203600061199286613041565b90508115806119a15750808210155b6040518060400160405280601e81526020017f4a525f494e56414c49445f444541435449564154494f4e5f414d4f554e54000081525090611a2657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50611a3133846136a6565b50505050505050565b6001600160a01b03811660009081526003602052604081206111b48161378a565b6000611a6561364e565b905061100d82826137ca565b6001600160a01b0316600090815260036020819052604090912001546001600160401b031690565b611aa1612677565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090611b3a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b506001600160a01b0391909116600090815260036020819052604090912001805467ffffffffffffffff19166001600160401b03909216919091179055565b6113ee33823361313a565b6000611b8e612677565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090611c2757604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5060408051808201909152601d81527f4a525f494e56414c49445f4c4f434b45445f414d4f554e54535f4c454e0000006020820152868514611cad57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5060408051808201909152601e81527f4a525f494e56414c49445f52455741524445445f4a55524f52535f4c454e00006020820152868314611d3357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50600188016000805b888110156112f6576000888883818110611d5257fe5b90506020020135905060008b8b84818110611d6957fe5b602090810292909201356001600160a01b0316600081815260039093526040909220600181015492935091611d9f915084612f85565b6001820155888885818110611db057fe5b9050602002013515611e00576040805184815290516001600160a01b038416917f04205018e3978d4e9bf2627d251200b16b790aff8c89cccc4b6e4b226c6c0531919081900360200190a2611e83565b611e10858463ffffffff61281916565b9450611e1e828460006129ef565b508054611e37906005908886600063ffffffff612a9616565b604080518481526001600160401b038816602082015281516001600160a01b038516927fb0f2cd2d530eb7a84b780655bd7cd315af71951aedf4ff554889d56cfc3c4ae9928290030190a25b505050600101611d3c565b610ab3338484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506138a592505050565b60606000611edb612677565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090611f7457604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50611f7d615031565b6040805160e0818101909252611fab9186906007908390839080828437600092019190915250613b73915050565b90508060800151604051908082528060200260200182016040528015611fdb578160200160208202803883390190505b50600060e083015292505b806080015182108015611ffd5750600a8160e00151105b1561219c5760608061200e83613c14565b909250905060005b8251811080156120295750836080015185105b156121895760006004600085848151811061204057fe5b60209081029190910181015182528181019290925260409081016000908120546001600160a01b0316808252600390935290812060c0880151600182015493945090926120929163ffffffff61281916565b905060006120a78389604001516001016127eb565b905060008686815181106120b757fe5b602002602001015190508281106121785760006120da828463ffffffff612f8516565b9050838110156120f5576120f5868286038c604001516128ae565b838560010181905550858c8c806001019d508151811061211157fe5b60200260200101906001600160a01b031690816001600160a01b031681525050856001600160a01b03167fab9783755c502b2e2e2a8f5d7c88344973a1400de6c46334a7d60d70a17f64588b60c001516040518082815260200191505060405180910390a2505b505060019093019250612016915050565b50505060e0810180516001019052611fe6565b50915091565b60015490565b6121b0613c5d565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f5200008152509061224957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b506113ee81613cac565b60006111b48383613e0a565b6001600160a01b031660009081526003602052604090205490565b60006122866005613e4b565b905090565b6002546001600160a01b031690565b54151590565b60006122af8460008585613e65565b949350505050565b600281015460018201546004909201549092565b60408051808201909152601681527f4a525f494e56414c49445f5a45524f5f414d4f554e540000000000000000000060208201528261234e57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5061235b838360016126c6565b600160e11b63593062150261236f826130ff565b6001600160e01b031916141561238a5761238a83838661313a565b826001600160a01b03167fc65e53b88159e7d2c0fc12a0600072e28ae53ff73b4c1715369c30f160935142836123bf8661263e565b846040518084815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156124095781810151838201526020016123f1565b50505050905090810190601f1680156124365780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a2600254612463906001600160a01b031685308563ffffffff613e9016565b6040518060400160405280601881526020017f4a525f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509061183357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b60008060009054906101000a90046001600160a01b03166001600160a01b0316636f85a7006040518163ffffffff1660e01b815260040160206040518083038186803b15801561149357600080fd5b60006125416124e8565b6001600160a01b031663ca6f0007836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561259657600080fd5b505afa1580156125aa573d6000803e3d6000fd5b505050506040513d60208110156125c057600080fd5b505192915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b03167fa9059cbb000000000000000000000000000000000000000000000000000000001790526000906126358582613f0f565b95945050505050565b60008060008061264d856130a0565b935050925092506126358161266b858561281990919063ffffffff16565b9063ffffffff61281916565b60008060009054906101000a90046001600160a01b03166001600160a01b031663db9bee466040518163ffffffff1660e01b815260040160206040518083038186803b15801561149357600080fd5b816126d057610ab3565b6001600160a01b0383166000908152600360205260409020811561270d576002810154612703908463ffffffff61281916565b6002820155610afa565b80600201548311156040518060400160405280601f81526020017f4a525f4e4f545f454e4f5547485f415641494c41424c455f42414c414e4345008152509061279a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b506002018054929092039091555050565b60006127b68261229a565b6127c1576000610f13565b60018201548254610f1391906127df9060059063ffffffff613f5a16565b9063ffffffff612f8516565b600582015460009060048401906001600160401b038481169116146128115760006122af565b549392505050565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f57000000000000000000000000000000602082015260009083830190848210156128a657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b509392505050565b6001600160a01b0383166000908152600360209081526040918290206004810180548451808601909552601f85527f4a525f43414e545f5245445543455f444541435449564154494f4e5f524551009385019390935290929091908582101561295b57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5084810380835561296e878760016129ef565b50835461298b906005906001808901908a9063ffffffff612a9616565b6001830154604080516001600160401b0392831681526020810184905291871682820152516001600160a01b038916917fc8eaece66ffd12e5066e2ef36d5943fa8fb8104362f92f75152c39788d85b184919081900360600190a250505050505050565b6000806129fb85612537565b6001600160a01b0381166000908152600860205260409020549091508315612a4b57612a2d818663ffffffff61281916565b6001600160a01b038316600090815260086020526040902055612a75565b612a5b818663ffffffff612f8516565b6001600160a01b0383166000908152600860205260409020555b506001600160a01b0316600090815260086020526040902054949350505050565b845460408051808201909152601b81527f53554d5f545245455f4b45595f444f45535f4e4f545f455849535400000000006020820152908510612b1d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b506000612b2a8686613f5a565b9050600082612b4857612b43828563ffffffff612f8516565b612b58565b612b58828563ffffffff61281916565b9050612b68876000888885613f68565b611a318787878787613f94565b612b7d615082565b6000612b876150b5565b6000612b916150d3565b612b996150f2565b612ba16150f2565b612ba9615110565b612bb1610ef9565b6001600160a01b031663e008cb628a6040518263ffffffff1660e01b815260040180826001600160401b03166001600160401b031681526020019150506102c06040518083038186803b158015612c0757600080fd5b505afa158015612c1b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102c0811015612c4157600080fd5b5080516080820151909850602082019750955060a0810194506101c08101935061020081019250610240019050612c76615082565b6040805160a0810182526001600160a01b038a16815260208681015161ffff168183015289518284015289810151606083015289830151608083015290835281516101a08101835260ff8916815287516001600160401b03169181019190915290810186600160200201516001600160401b0316815260200186600260098110612cfc57fe5b60200201516001600160401b0316815260200186600360098110612d1c57fe5b60200201516001600160401b0316815260200186600460098110612d3c57fe5b60200201516001600160401b0316815260200185600060028110612d5c57fe5b602002015161ffff16815260200186600560098110612d7757fe5b60200201516001600160401b0316815260200186600660098110612d9757fe5b60200201516001600160401b0316815260200186600860098110612db757fe5b60200201516001600160401b0316815260200186600760098110612dd757fe5b60200201516001600160401b0316815260200184600060028110612df757fe5b6020020151815260200184600160028110612e0e57fe5b60200201518152508160200181905250604051806080016040528083600060048110612e3657fe5b6020020151815260200183600160048110612e4d57fe5b6020020151815260200183600260048110612e6457fe5b6020020151815260200183600360048110612e7b57fe5b6020020151905260408201529998505050505050505050565b600080612e9f6140b6565b6001600160401b0316836001600160401b03161015905080612ed157612ecc60058463ffffffff6140f816565b6111b4565b6111b460058463ffffffff61411416565b600082612ef157506000610f13565b82820282848281612efe57fe5b04146040518060400160405280601181526020017f4d4154485f4d554c5f4f564552464c4f57000000000000000000000000000000815250906128a657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b6000828211156040518060400160405280601281526020017f4d4154485f5355425f554e444552464c4f5700000000000000000000000000008152509061301057604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5050900390565b6000670de0b6b3a7640000613032848463ffffffff612ee216565b8161303957fe5b049392505050565b600061304b610ef9565b6001600160a01b03166395f3c2da836040518263ffffffff1660e01b815260040180826001600160401b03166001600160401b0316815260200191505060206040518083038186803b15801561259657600080fd5b6001600160a01b03811660009081526003602052604081208190819081906130c78161229a565b6130d25760006130e6565b80546130e69060059063ffffffff613f5a16565b94506130f1816122b7565b969891975095945092505050565b600060048251101561311357506000610bc0565b506020015190565b6000816020018351101561313157506000610f13565b50016020015190565b600061314461364e565b905061315084826137ca565b6001600160a01b038416600090815260036020526040812060020154908415613179578461317b565b815b9050600081116040518060400160405280601681526020017f4a525f494e56414c49445f5a45524f5f414d4f554e54000000000000000000008152509061320657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5060408051808201909152601c81527f4a525f494e56414c49445f41435449564154494f4e5f414d4f554e540000000060208201528282111561328d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b506001830161329c8183614130565b6001600160a01b0387166000908152600360205260408120906132be83613041565b905060006132cb876111bb565b90506132d68361229a565b156133b15782546000906132f29060059063ffffffff613f5a16565b90506000613306828863ffffffff61281916565b9050838110156040518060400160405280601b81526020017f4a525f4143544956455f42414c414e43455f42454c4f575f4d494e00000000008152509061339157604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5084546133aa90600590888a600163ffffffff612a9616565b5050613482565b60408051808201909152601b81527f4a525f4143544956455f42414c414e43455f42454c4f575f4d494e000000000060208201528286101561343757604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5061344a6005858763ffffffff6141dc16565b8084556000908152600460205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038c161790555b60006134908b8760016129ef565b9050818111156040518060400160405280601b81526020017f4a525f4143544956455f42414c414e43455f41424f56455f4d415800000000008152509061351b57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b506135288b8760006126c6565b604080516001600160401b0387168152602081018890526001600160a01b038b8116828401529151918d16917fee90556a99bb0d072721fedb6d8d458371d132b715762b023fba4d367fbd57b29181900360600190a25050505050505050505050565b6060818301845110156135ad57506040805160008152602081019091526111b4565b6060826040519080825280601f01601f1916602001820160405280156135da576020820181803883390190505b509050835b838501811015613645578581815181106135f557fe5b602001015160f81c60f81b828683038151811061360e57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506001016135df565b50949350505050565b6000613658610ef9565b6001600160a01b0316633f33bf866040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561369257600080fd5b505af11580156114a7573d6000803e3d6000fd5b60006136b061364e565b90506136bc83826137ca565b6001600160a01b0383166000908152600360205260409020600481018054600184019291906136f1908663ffffffff61281916565b815560018101805467ffffffffffffffff19166001600160401b03851617905561371d868660006129ef565b508154613736906005908588600063ffffffff612a9616565b604080516001600160401b03851681526020810187905281516001600160a01b038916927fe26ea88625a55cdd86472d3d0e9efd8dd884b5baa05b79bb95a3408df76cede9928290030190a2505050505050565b6000806137956140b6565b90506137a08361229a565b6137ab5760006111b4565b600183015483546111b491906127df906005908563ffffffff6122a016565b6001600160a01b0382166000908152600360205260409020600581015460048201906001600160401b03168015806138135750806001600160401b0316846001600160401b0316105b156138205750505061100d565b81546001808401805467ffffffffffffffff191690556000845561384790879083906126c6565b604080516001600160401b0380851682526020820184905287168183015290516001600160a01b038816917f8969a0b11c2c7f08ef80af31a680937503d444cdc933ba9091cdc20f098a7f36919081900360600190a2505050505050565b60408051808201909152601681527f4a525f494e56414c49445f5a45524f5f414d4f554e540000000000000000000060208201528261392857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5060006139336140b6565b6001600160a01b038516600090815260036020819052604090912001549091506001600160401b031680158061397a5750816001600160401b0316816001600160401b0316105b6040518060400160405280601381526020017f4a525f5749544844524157414c535f4c4f434b00000000000000000000000000815250906139ff57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50613a0a85836137ca565b613a16858560006126c6565b846001600160a01b03167faf01bfc8475df280aca00b578c4a948e6d95700f0db8c13365240f7f973c875485613a4b8861263e565b866040518084815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015613a95578181015183820152602001613a7d565b50505050905090810190601f168015613ac25780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a2600254613aee906001600160a01b0316868663ffffffff6125c816565b6040518060400160405280601881526020017f4a525f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509061173357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b613b7b615031565b60408201516000613b8b82613041565b905060405180610100016040528085600060078110613ba657fe5b60209081029190910151825286810151908201526001600160401b0384166040820152606080870151908201526080808701519082015260a0808701519082015260c001613c028660066020020151849063ffffffff61421416565b81526000602090910152949350505050565b606080613c53836000015184602001518560400151866060015187608001518860a001518960e00151600561422d90979695949392919063ffffffff16565b9094909350915050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166397023f816040518163ffffffff1660e01b815260040160206040518083038186803b15801561149357600080fd5b60408051808201909152601d81527f4a525f4241445f544f54414c5f4143544956455f42414c5f4c494d4954000000602082015281613d2f57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50613d40613d3b6140b6565b6111bb565b81116040518060400160405280601f81526020017f4a525f544f54414c5f4143544956455f42414c414e43455f544f4f5f4c4f570081525090613dc757604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50600154604080519182526020820183905280517f9ce60e2304bd08c7c9e6da0e10912e44f85fd9e2ee71c1842132f12146c586c89281900390910190a1600155565b6001600160a01b0382166000908152600360205260408120613e2b8161229a565b613e365760006122af565b80546122af906005908563ffffffff6122a016565b600080613e578361438f565b90506111b48382600061439d565b600083815260028501602090815260408083208584529091528120612635908363ffffffff6143c116565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03167f23b872dd00000000000000000000000000000000000000000000000000000000179052600090613f058682613f0f565b9695505050505050565b6000806040516020818551602087016000895af18015613f50573d8015613f3d5760208114613f4657613f4e565b60019350613f4e565b600183511493505b505b5090949350505050565b60006111b48360008461439d565b60008481526002860160209081526040808320868452909152902061183390838363ffffffff6143cd16565b600019846000613fa38861438f565b905060015b81811161400e5760049390931b92918316916000613fc78a838661439d565b9050600086613fe557613fe0828963ffffffff612f8516565b613ff5565b613ff5828963ffffffff61281916565b90506140048b84878c85613f68565b5050600101613fa8565b5083158061402657508461402389838561439d565b10155b6040518060400160405280601881526020017f53554d5f545245455f5550444154455f4f564552464c4f570000000000000000815250906140ab57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b505050505050505050565b60006140c0610ef9565b6001600160a01b031663f7fe57896040518163ffffffff1660e01b815260040160206040518083038186803b15801561149357600080fd5b6000806141058484614466565b90506122af8482600086613e65565b6000806141218484614466565b90506122af848260008661447b565b600061413b83612e94565b9050600061414f828463ffffffff61281916565b90506001548111156040518060400160405280602081526020017f4a525f544f54414c5f4143544956455f42414c414e43455f45584345454445448152509061183357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b82546001810184556000906141f28582866144a6565b82156122af57614206856000838787613f68565b6122af858286866001613f94565b60006127106130328461ffff851663ffffffff612ee216565b6060806000806142408c8a8a8a8a6144f7565b9150915060606142548c8c888b8787614565565b90506142678d828c63ffffffff61475d16565b8051825160408051808201909152601f81527f545245455f534f52544954494f4e5f4c454e475448535f4d49534d41544348006020820152939850919650146142f457604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50878551146040518060400160405280601f81526020017f545245455f534f52544954494f4e5f4c454e475448535f4d49534d41544348008152509061437e57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b505050509850989650505050505050565b6000610f138260010161497a565b6000828152600284016020908152604080832084845290915281206122af9061497a565b60006111b483836149c5565b60408051808201909152601881527f434845434b504f494e545f56414c55455f544f4f5f424947000000000000000060208201526001600160c01b0382111561445a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b50610ab3838383614b52565b60006111b4600184018363ffffffff614cdd16565b600083815260028501602090815260408083208584529091528120612635908363ffffffff614cdd16565b60006144b18461438f565b90506144bd8184614ce9565b15610afa576001810160006144d386848361439d565b90506144e3868360008785613f68565b61173360018701858463ffffffff6143cd16565b6000808061450b888863ffffffff61411416565b905061452d84614521888463ffffffff612ee216565b9063ffffffff614d0f16565b92506000614541878763ffffffff61281916565b905061455785614521838563ffffffff612ee216565b925050509550959350505050565b60608282116040518060400160405280601c81526020017f545245455f494e56414c49445f494e54455256414c5f53454152434800000000815250906145ef57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5060008383039050606085604051908082528060200260200182016040528015614623578160200160208202803883390190505b50905060005b86811015614750576040805160208082018d90528183018c9052606082018b905260808083018590528351808403909101815260a0909201909252805191012061468484828161467557fe5b8991900663ffffffff61281916565b83838151811061469057fe5b6020908102919091010152815b6000811180156146d557508360018203815181106146b757fe5b60200260200101518482815181106146cb57fe5b6020026020010151105b156147465760008460018303815181106146eb57fe5b6020026020010151905084828151811061470157fe5b602002602001015185600184038151811061471857fe5b6020026020010181815250508085838151811061473157fe5b6020908102919091010152506000190161469d565b5050600101614629565b5098975050505050505050565b60608060008451116040518060400160405280601e81526020017f53554d5f545245455f4d495353494e475f5345415243485f56414c5545530000815250906147ea57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5060006147f78685614114565b905060008111801561481f57508460018651038151811061481457fe5b602002602001015181115b6040518060400160405280601d81526020017f53554d5f545245455f5345415243485f4f55545f4f465f424f554e4453000000815250906148a457604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5060006148b18786614466565b90506148bb61512e565b6040805160a081019091526001600160401b0387168152602081016148e784600163ffffffff612f8516565b815260200160008152602001600081526020016000815250905060008751905080604051908082528060200260200182016040528015614931578160200160208202803883390190505b5095508060405190808252806020026020018201604052801561495e578160200160208202803883390190505b50945061496e8989848989614dae565b50505050935093915050565b805460009080156149bc5782600001600182038154811061499757fe5b600091825260209091200154600160401b90046001600160c01b03169150610bc09050565b50600092915050565b8154600090806149d9576000915050610f13565b83546000198201908590829081106149ed57fe5b6000918252602090912001546001600160401b0390811690851610614a4157846000018181548110614a1b57fe5b600091825260209091200154600160401b90046001600160c01b03169250610f13915050565b84600001600081548110614a5157fe5b6000918252602090912001546001600160401b039081169085161015614a7c57600092505050610f13565b6000815b81811115614b1c57865460028383016001010490600090899083908110614aa357fe5b600091825260209091200180549091506001600160401b03908116908916811015614ad057829450614b14565b806001600160401b0316896001600160401b03161015614af557600183039350614b14565b5054600160401b90046001600160c01b03169550610f13945050505050565b505050614a80565b866000018281548110614b2b57fe5b600091825260209091200154600160401b90046001600160c01b0316979650505050505050565b8254801580614b90575083546001600160401b0384169085906000198101908110614b7957fe5b6000918252602090912001546001600160401b0316105b15614c0057604080518082019091526001600160401b0380851682526001600160c01b0380851660208085019182528854600181018a5560008a8152919091209451940180549151909216600160401b0293831667ffffffffffffffff1990911617909116919091179055610afa565b6000846000016001830381548110614c1457fe5b6000918252602091829020018054604080518082019091528381527f434845434b504f494e545f43414e4e4f545f4144445f504153545f56414c5545938101939093529092506001600160401b03868116911614614cb657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b5080546001600160c01b038416600160401b026001600160401b0390911617905550505050565b60006111b48383614ef5565b600080614cfd84600463ffffffff612ee216565b600019901b8316151591505092915050565b60008082116040518060400160405280600d81526020017f4d4154485f4449565f5a45524f0000000000000000000000000000000000000081525090614d9957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610cce578181015183820152602001610cb6565b506000828481614da557fe5b04949350505050565b6020830151600090614dc790600463ffffffff612ee216565b905060005b6010811015611a31578551856060015110614de657611a31565b6040850151600090614e009083851b63ffffffff61281916565b90506000614e18898860200151848a6000015161447b565b90506000614e3382896080015161281990919063ffffffff16565b90506000614e468a8a6060015184614fab565b90508015614ee5576020890151614e6e57614e69896060015182868b878c614fe9565b614eca565b614e7661512e565b6040518060a001604052808b600001516001600160401b0316815260200160018c602001510381526020018681526020018b6060015181526020018b608001518152509050614ec88c8c838c8c614dae565b505b6060890151614edf908263ffffffff61281916565b60608a01525b5060808801525050600101614dcc565b815460009080614f09576000915050610f13565b8354600019820190600090869083908110614f2057fe5b9060005260206000200190505b600082118015614f49575080546001600160401b038087169116115b15614f7457855460001990920191869083908110614f6357fe5b906000526020600020019050614f2d565b80546001600160401b03808716911611614f9f578054600160401b90046001600160c01b0316613f05565b60009695505050505050565b6000825b845181108015614fd1575082858281518110614fc757fe5b6020026020010151105b15614fde57600101614faf565b929092039392505050565b60005b85811015611a315784848289018151811061500357fe5b60200260200101818152505082828289018151811061501e57fe5b6020908102919091010152600101614fec565b604051806101000160405280600080191681526020016000815260200160006001600160401b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806102c00160405280615096615166565b81526020016150a36151a2565b81526020016150b061520e565b905290565b60405180606001604052806003906020820280388339509192915050565b6040518061012001604052806009906020820280388339509192915050565b60405180604001604052806002906020820280388339509192915050565b60405180608001604052806004906020820280388339509192915050565b6040518060a0016040528060006001600160401b03168152602001600081526020016000815260200160008152602001600081525090565b6040518060a0016040528060006001600160a01b03168152602001600061ffff1681526020016000815260200160008152602001600081525090565b604080516101a081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081019190915290565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b61524d60018281019060009063ffffffff6143cd16565b6000905556fea165627a7a72305820e57bffe1a1fdbddc43338eb47739430057a11db435c000010b8722ae74145e920029000000000000000000000000f0c8376065fadfacb706cafbaac96b321069c015000000000000000000000000000000000001c6bf52633ffffbb9c3a1c12e0000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f0c8376065fadfacb706cafbaac96b321069c015000000000000000000000000000000000001c6bf52633ffffbb9c3a1c12e0000
-----Decoded View---------------
Arg [0] : _controller (address): 0xf0c8376065fadfacb706cafbaac96b321069c015
Arg [1] : _totalActiveBalanceLimit (uint256): 9223372036854775500000000000000000
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000f0c8376065fadfacb706cafbaac96b321069c015
Arg [1] : 000000000000000000000000000000000001c6bf52633ffffbb9c3a1c12e0000
Deployed ByteCode Sourcemap
170956:51923:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;170956:51923:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;197415:388;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;197415:388:0;;-1:-1:-1;;;;;197415:388:0;;;;;-1:-1:-1;;;;;197415:388:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;180716:128;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;180716:128:0;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;180716:128:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;180716:128:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;180716:128:0;;-1:-1:-1;180716:128:0;-1:-1:-1;180716:128:0;:::i;:::-;;181164:137;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;181164:137:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;181164:137:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;181164:137:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;181164:137:0;;-1:-1:-1;181164:137:0;-1:-1:-1;181164:137:0;:::i;199016:317::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;199016:317:0;-1:-1:-1;;;;;199016:317:0;;:::i;:::-;;;;;;;;;;;;;;;;169732:346;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;169732:346:0;;;;;;;;;;:::i;164812:96::-;;;:::i;:::-;;;;-1:-1:-1;;;;;164812:96:0;;;;;;;;;;;;;;196101:121;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;196101:121:0;-1:-1:-1;;;;;196101:121:0;;:::i;184287:249::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;184287:249:0;;;;;;;;:::i;191734:1724::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;191734:1724:0;;-1:-1:-1;;;;;191734:1724:0;;;;;;;;;;-1:-1:-1;;;;;191734:1724:0;;:::i;:::-;;;;;;;;;;;;;;;;;;199681:1482;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;199681:1482:0;-1:-1:-1;;;;;199681:1482:0;;:::i;184671:227::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;184671:227:0;;:::i;201449:270::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;201449:270:0;-1:-1:-1;;;;;201449:270:0;;:::i;:::-;;;;;;;-1:-1:-1;;;;;201449:270:0;;;;;;;;;;;;;;;;202965:87;;;:::i;196679:182::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;196679:182:0;-1:-1:-1;;;;;196679:182:0;;:::i;194817:117::-;;;:::i;182736:926::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;182736:926:0;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;182736:926:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;182736:926:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;182736:926:0;;-1:-1:-1;182736:926:0;-1:-1:-1;182736:926:0;:::i;195413:134::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;195413:134:0;-1:-1:-1;;;;;195413:134:0;;:::i;182039:266::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;182039:266:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;182039:266:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;182039:266:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;182039:266:0;;-1:-1:-1;182039:266:0;-1:-1:-1;182039:266:0;:::i;179547:902::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;179547:902:0;;:::i;198580:201::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;198580:201:0;-1:-1:-1;;;;;198580:201:0;;:::i;183851:170::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;183851:170:0;-1:-1:-1;;;;;183851:170:0;;:::i;201942:152::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;201942:152:0;-1:-1:-1;;;;;201942:152:0;;:::i;:::-;;;;-1:-1:-1;;;;;201942:152:0;;;;;;;;;;;;;;193814:197;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;193814:197:0;;-1:-1:-1;;;;;193814:197:0;;;;;-1:-1:-1;;;;;193814:197:0;;:::i;179209:111::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;179209:111:0;;:::i;189612:1472::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;189612:1472:0;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;189612:1472:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;189612:1472:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;189612:1472:0;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;189612:1472:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;189612:1472:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;189612:1472:0;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;189612:1472:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;189612:1472:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;189612:1472:0;;-1:-1:-1;189612:1472:0;-1:-1:-1;189612:1472:0;:::i;181544:120::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;181544:120:0;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;181544:120:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;181544:120:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;181544:120:0;;-1:-1:-1;181544:120:0;-1:-1:-1;181544:120:0;:::i;185577:3423::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;185577:3423:0;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;185577:3423:0;;;;;;;;;;;;;;;;;;202703:122;;;:::i;194224:170::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;194224:170:0;;:::i;198109:152::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;198109:152:0;;-1:-1:-1;;;;;198109:152:0;;;;;-1:-1:-1;;;;;198109:152:0;;:::i;202378:120::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;202378:120:0;-1:-1:-1;;;;;202378:120:0;;:::i;195067:103::-;;;:::i;194540:95::-;;;:::i;197415:388::-;-1:-1:-1;;;;;197618:23:0;;197500:14;197618:23;;;:15;:23;;;;;197500:14;;;;;;197663:19;197618:23;197663:12;:19::i;:::-;:59;;197721:1;197663:59;;;197700:8;;197685:33;;:4;;197710:7;197685:33;:14;:33;:::i;:::-;197654:68;;197776:19;197789:5;197776:12;:19::i;:::-;197415:388;;197733:62;;-1:-1:-1;197733:62:0;-1:-1:-1;197415:388:0;-1:-1:-1;;;;197415:388:0:o;180716:128::-;180790:46;180797:10;180809;180821:7;180830:5;;180790:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;180790:6:0;;-1:-1:-1;;;180790:46:0:i;:::-;180716:128;;;:::o;181164:137::-;181254:39;181261:10;181273:3;181278:7;181287:5;;181254:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;181254:6:0;;-1:-1:-1;;;181254:39:0:i;:::-;181164:137;;;;:::o;199016:317::-;199087:7;199111:19;:17;:19::i;:::-;-1:-1:-1;;;;;199111:35:0;;199147:6;199111:43;;;;;;;;;;;;;-1:-1:-1;;;;;199111:43:0;-1:-1:-1;;;;;199111:43:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;199111:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;199111:43:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;199111:43:0;199107:219;;;199171:21;199195:22;199210:6;199195:14;:22::i;:::-;-1:-1:-1;;;;;199239:34:0;;;;;:19;:34;;;;;;;-1:-1:-1;199232:41:0;;-1:-1:-1;199232:41:0;199107:219;-1:-1:-1;199313:1:0;199107:219;199016:317;;;:::o;169732:346::-;169179:10;;;;;;;;;-1:-1:-1;;;;;169179:10:0;-1:-1:-1;;;;;169179:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;169179:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;169179:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;169179:29:0;169210:31;;;;;;;;;;;;;169179:29;169210:31;;;;-1:-1:-1;;;;;169165:43:0;:10;:43;169157:85;;;;-1:-1:-1;;;;;169157:85: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;169157:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;169837:31:0;;;-1:-1:-1;;;;;169837:31:0;;169862:4;169837:31;;;;;;169819:15;;-1:-1:-1;;;;;169837:16:0;;;;;:31;;;;;;;;;;;;;;;:16;:31;;;5:2:-1;;;;30:1;27;20:12;5:2;169837:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;169837:31:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;169837:31:0;169900:32;;;;;;;;;;;;;169837:31;169900:32;;;169837:31;;-1:-1:-1;169887:11:0;169879:54;;;;-1:-1:-1;;;;;169879:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;169879:54:0;-1:-1:-1;169952:33:0;-1:-1:-1;;;;;169952:19:0;;169972:3;169977:7;169952:33;:19;:33;:::i;:::-;169987:32;;;;;;;;;;;;;;;;;169944:76;;;;;-1:-1:-1;;;;;169944:76:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;169944:76:0;-1:-1:-1;170036:34:0;;;-1:-1:-1;;;;;170036:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;169253:1;169732:346;;:::o;164812:96::-;164860:10;164890;-1:-1:-1;;;;;164890:10:0;164812:96;:::o;196101:121::-;196164:7;196191:23;196207:6;196191:15;:23::i;:::-;196184:30;196101:121;-1:-1:-1;;196101:121:0:o;184287:249::-;164347:17;:15;:17::i;:::-;-1:-1:-1;;;;;164325:40:0;:10;-1:-1:-1;;;;;164325:40:0;;164367:32;;;;;;;;;;;;;;;;;164317:83;;;;;-1:-1:-1;;;;;164317:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;164317:83:0;-1:-1:-1;184385:11:0;;184381:148;;184413:48;184439:6;184447:7;184456:4;184413:25;:48::i;:::-;184481:36;;;;;;;;-1:-1:-1;;;;;184481:36:0;;;;;;;;;;;;;184381:148;184287:249;;:::o;191734:1724::-;191843:4;164347:17;:15;:17::i;:::-;-1:-1:-1;;;;;164325:40:0;:10;-1:-1:-1;;;;;164325:40:0;;164367:32;;;;;;;;;;;;;;;;;164317:83;;;;;-1:-1:-1;;;;;164317:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;164317:83:0;-1:-1:-1;191864:12:0;191860:56;;-1:-1:-1;191900:4:0;191893:11;;191860:56;-1:-1:-1;;;;;191992:23:0;;191928:17;191992:23;;;:15;:23;;;;;191958:1;191948:11;;;192058:35;191992:23;192058:28;:35::i;:::-;192026:67;;192104:41;192148:54;192184:5;192191:10;192148:35;:54::i;:::-;192104:98;-1:-1:-1;192391:34:0;192428:60;:21;192104:98;192428:60;:25;:60;:::i;:::-;192391:97;;192513:26;192503:7;:36;192499:81;;;192563:5;192556:12;;;;;;;;;192499:81;192986:21;192976:7;:31;192972:267;;;193122:31;;;193168:59;193195:6;193122:31;193219:7;193168:26;:59::i;:::-;192972:267;;193251:50;193278:6;193286:7;193295:5;193251:26;:50::i;:::-;-1:-1:-1;193324:8:0;;193312:49;;:4;;193334:10;193346:7;193324:8;193312:49;:11;:49;:::i;:::-;193379;;;;;;-1:-1:-1;;;;;193379:49:0;;;;;;;;-1:-1:-1;;;;;193379:49:0;;;;;;;;;;;193446:4;193439:11;;;;;;;164411:1;191734:1724;;;;;:::o;199681:1482::-;199744:7;199764:12;199779:8;:6;:8::i;:::-;199764:23;;199798:31;199832:5;-1:-1:-1;;;;;199832:29:0;;199862:7;199832:38;;;;;;;;;;;;;-1:-1:-1;;;;;199832:38:0;-1:-1:-1;;;;;199832:38:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;199832:38:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;199832:38:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;199832:38:0;;-1:-1:-1;199885:28:0;199881:69;;199937:1;199930:8;;;;;;199881:69;199962:28;199993:21;200006:7;199993:12;:21::i;:::-;:28;;;:49;;;199962:80;;200053:28;200084:21;200097:7;200084:12;:21::i;:::-;:28;;;;;:49;;;-1:-1:-1;200164:43:0;;;200144:17;200327:30;200349:7;200327:21;:30::i;:::-;200292:65;-1:-1:-1;200370:31:0;200404:91;200471:23;200429:39;200292:65;200458:9;200429:39;:28;:39;:::i;:::-;:65;;;;;200404:20;;200429:65;;200404:91;:24;:91;:::i;:::-;200370:125;-1:-1:-1;200506:24:0;200533:65;:23;200370:125;200533:65;:40;:65;:::i;:::-;200506:92;;200946:24;200973:33;200994:7;201004:1;200994:11;200973:20;:33::i;:::-;200946:60;;201040:16;201021;:35;201017:103;;;201092:16;201073:35;;201017:103;-1:-1:-1;201139:16:0;199681:1482;-1:-1:-1;;;;;;;;;199681:1482:0:o;184671:227::-;164347:17;:15;:17::i;:::-;-1:-1:-1;;;;;164325:40:0;:10;-1:-1:-1;;;;;164325:40:0;;164367:32;;;;;;;;;;;;;;;;;164317:83;;;;;-1:-1:-1;;;;;164317:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;164317:83:0;-1:-1:-1;184751:11:0;;184747:144;;184779:54;173102:42;184819:7;184828:4;184779:25;:54::i;:::-;184853:26;;;;;;;;;;;;;;;;;184747:144;184671:227;:::o;201449:270::-;-1:-1:-1;;;;;201609:23:0;;201520:14;201609:23;;;:15;:23;;;;;:43;;;201671:14;201687:23;;;;;-1:-1:-1;;;;;201687:23:0;201449:270;;;:::o;202965:87::-;203015:4;202965:87;:::o;196679:182::-;196737:14;196753:17;196772:14;196788:27;196835:18;196846:6;196835:10;:18::i;:::-;196828:25;;;;;;;;196679:182;;;;;:::o;194817:117::-;194890:11;;:36;;;-1:-1:-1;;;;;194890:36:0;;194920:4;194890:36;;;;;;194863:7;;-1:-1:-1;;;;;194890:11:0;;:21;;:36;;;;;;;;;;;;;;:11;:36;;;5:2:-1;;;;30:1;27;20:12;5:2;194890:36:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;194890:36:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;194890:36:0;;-1:-1:-1;194817:117:0;:::o;182736:926::-;182890:19;:17;:19::i;:::-;-1:-1:-1;;;;;182868:42:0;:10;-1:-1:-1;;;;;182868:42:0;;182912:34;;;;;;;;;;;;;;;;;182860:87;;;;;-1:-1:-1;;;;;182860:87:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;182860:87:0;;182960:23;182986:16;:5;;:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;182986:14:0;;-1:-1:-1;;;182986:16:0:i;:::-;182960:42;;183013:14;183030:18;183046:1;183030:5;;:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;183030:15:0;;:18;-1:-1:-1;;183030:18:0;:15;:18;;-1:-1:-1;183030:18:0:i;:::-;183013:35;-1:-1:-1;;;;;;;183104:58:0;;-1:-1:-1;;;;;183104:58:0;183100:555;;;183179:65;183195:19;183216:6;183224:19;183179:15;:65::i;:::-;183100:555;;;-1:-1:-1;;;;;;183268:55:0;;183288:35;183268:55;183264:391;;;183340:21;183364:26;183383:3;183388:1;183364:5;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;183364:18:0;;:26;;-1:-1:-1;;183364:26:0;:18;:26;;-1:-1:-1;183364:26:0:i;:::-;183340:50;;183511:66;183518:19;183539;183560:6;183568:8;183511:6;:66::i;:::-;183264:391;;;;183619:23;;;;;;;;;;;;;;;;;;;183612:31;;-1:-1:-1;;;;;183612:31:0;;;;;;;;;;;;;;;;183619:23;;183612:31;;;;;;;;183619:23;183612:31;;183619:23;-1:-1:-1;27:10;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;183264:391:0;182736:926;;;;;;:::o;195413:134::-;195482:7;195509:30;195531:7;195509:21;:30::i;182039:266::-;182162:10;-1:-1:-1;;;;;182162:20:0;;;:54;;;;-1:-1:-1;182204:11:0;;-1:-1:-1;;;;;182186:30:0;;;182204:11;;182186:30;182162:54;182218:31;;;;;;;;;;;;;;;;;182154:96;;;;;-1:-1:-1;;;;;182154:96:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;182154:96:0;;182261:36;182268:5;182275;182282:7;182291:5;;182261:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;182261:6:0;;-1:-1:-1;;;182261:36:0:i;:::-;182039:266;;;;;:::o;179547:902::-;179604:13;179620:20;:18;:20::i;:::-;179689:10;179651:19;179673:27;;;:15;:27;;;;;179604:36;;-1:-1:-1;179743:35:0;179673:27;179743:28;:35::i;:::-;179711:67;-1:-1:-1;179789:26:0;179818:12;;:46;;179857:7;179818:46;;;179833:21;179818:46;179789:75;;179904:1;179883:18;:22;179907:25;;;;;;;;;;;;;;;;;179875:58;;;;;-1:-1:-1;;;;;179875:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;179875:58:0;-1:-1:-1;179997:33:0;;;;;;;;;;;;;;;;;179952:43;;;;179944:87;;;;-1:-1:-1;;;;;179944:87:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;179944:87:0;-1:-1:-1;180140:42:0;;;180110:27;180220:28;180241:6;180220:20;:28::i;:::-;180193:55;-1:-1:-1;180267:24:0;;;:67;;;180318:16;180295:19;:39;;180267:67;180336:33;;;;;;;;;;;;;;;;;180259:111;;;;;-1:-1:-1;;;;;180259:111:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;180259:111:0;;180383:58;180410:10;180422:18;180383:26;:58::i;:::-;179547:902;;;;;;;:::o;198580:201::-;-1:-1:-1;;;;;198694:23:0;;198652:7;198694:23;;;:15;:23;;;;;198735:38;198694:23;198735:31;:38::i;183851:170::-;183923:13;183939:20;:18;:20::i;:::-;183923:36;;183970:43;183998:6;184006;183970:27;:43::i;201942:152::-;-1:-1:-1;;;;;202041:23:0;202015:6;202041:23;;;:15;:23;;;;;;;;:45;;-1:-1:-1;;;;;202041:45:0;;201942:152::o;193814:197::-;164347:17;:15;:17::i;:::-;-1:-1:-1;;;;;164325:40:0;:10;-1:-1:-1;;;;;164325:40:0;;164367:32;;;;;;;;;;;;;;;;;164317:83;;;;;-1:-1:-1;;;;;164317:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;164317:83:0;-1:-1:-1;;;;;;193932:23:0;;;;193910:19;193932:23;;;:15;:23;;;;;;;;193966:27;:37;;-1:-1:-1;;193966:37:0;-1:-1:-1;;;;;193966:37:0;;;;;;;;;193814:197::o;179209:111::-;179264:48;179280:10;179292:7;179301:10;179264:15;:48::i;189612:1472::-;189811:7;164347:17;:15;:17::i;:::-;-1:-1:-1;;;;;164325:40:0;:10;-1:-1:-1;;;;;164325:40:0;;164367:32;;;;;;;;;;;;;;;;;164317:83;;;;;-1:-1:-1;;;;;164317:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;164317:83:0;-1:-1:-1;189885:35:0;;;;;;;;;;;;;;;;;189844:39;;;189836:85;;;;-1:-1:-1;;;;;189836:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;189836:85:0;-1:-1:-1;189982:36:0;;;;;;;;;;;;;;;;;189940:40;;;189932:87;;;;-1:-1:-1;;;;;189932:87:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;189932:87:0;-1:-1:-1;190062:1:0;190052:11;;190032:17;;190110:932;190130:18;;;190110:932;;;190170:20;190193:14;;190208:1;190193:17;;;;;;;;;;;;;190170:40;;190225:20;190248:7;;190256:1;190248:10;;;;;;;;;;;;;;;;-1:-1:-1;;;;;190248:10:0;190273:19;190295:29;;;:15;:29;;;;;;;190361:19;;;;190248:10;;-1:-1:-1;190295:29:0;190361:37;;-1:-1:-1;190385:12:0;190361:23;:37::i;:::-;190339:19;;;:59;190598:15;;190614:1;190598:18;;;;;;;;;;;;;;190594:437;;190642:48;;;;;;;;-1:-1:-1;;;;;190642:48:0;;;;;;;;;;;;;190594:437;;;190749:33;:15;190769:12;190749:33;:19;:33;:::i;:::-;190731:51;;190803:61;190830:12;190844;190858:5;190803:26;:61::i;:::-;-1:-1:-1;190895:8:0;;190883:54;;:4;;190905:10;190917:12;190895:8;190883:54;:11;:54;:::i;:::-;190963:52;;;;;;-1:-1:-1;;;;;190963:52:0;;;;;;;;-1:-1:-1;;;;;190963:52:0;;;;;;;;;;;190594:437;-1:-1:-1;;;190150:3:0;;190110:932;;181544:120;181620:36;181629:10;181641:7;181650:5;;181620:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;181620:8:0;;-1:-1:-1;;;181620:36:0:i;185577:3423::-;185658:23;185683:14;164347:17;:15;:17::i;:::-;-1:-1:-1;;;;;164325:40:0;:10;-1:-1:-1;;;;;164325:40:0;;164367:32;;;;;;;;;;;;;;;;;164317:83;;;;;-1:-1:-1;;;;;164317:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;164317:83:0;;185710:30;;:::i;:::-;185743:26;;;;;;;;;;;;185761:7;;185743:26;;;;185761:7;;185743:26;185761:7;185743:26;1:33:-1;99:1;81:16;;74:27;;;;-1:-1;185743:17:0;;-1:-1:-1;;185743:26:0:i;:::-;185710:59;;185803:11;:32;;;185789:47;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;185789:47:0;-1:-1:-1;186420:1:0;186396:21;;;:25;185780:56;-1:-1:-1;186391:2602:0;186445:11;:32;;;186436:6;:41;:89;;;;;173331:2;186481:11;:21;;;:44;186436:89;186391:2602;;;186591:25;186618:31;186653:24;186665:11;186653;:24::i;:::-;186590:87;;-1:-1:-1;186590:87:0;-1:-1:-1;186699:9:0;186694:2288;186718:8;:15;186714:1;:19;:64;;;;;186746:11;:32;;;186737:6;:41;186714:64;186694:2288;;;186928:20;186951:17;:30;186969:8;186978:1;186969:11;;;;;;;;;;;;;;;;;;;186951:30;;;;;;;;;;;;;-1:-1:-1;186951:30:0;;;;-1:-1:-1;;;;;186951:30:0;187022:29;;;:15;:29;;;;;;187230:27;;;;186951:30;187206:19;;;186951:30;;-1:-1:-1;187022:29:0;;187206:52;;;:23;:52;:::i;:::-;187179:79;;187514:41;187558:66;187594:5;187601:11;:18;;;187622:1;187601:22;187558:35;:66::i;:::-;187514:110;;187768:28;187799:14;187814:1;187799:17;;;;;;;;;;;;;;187768:48;;187863:16;187839:20;:40;187835:1132;;188269:29;188301:59;:20;188326:33;188301:59;:24;:59;:::i;:::-;188269:91;;188411:16;188387:21;:40;188383:281;;;188538:102;188565:12;188598:21;188579:16;:40;188621:11;:18;;;188538:26;:102::i;:::-;188788:16;188766:5;:19;;:38;;;;188846:12;188827:6;188834:8;;;;;;188827:16;;;;;;;;;;;;;:31;-1:-1:-1;;;;;188827:31:0;;;-1:-1:-1;;;;;188827:31:0;;;;;188905:12;-1:-1:-1;;;;;188886:61:0;;188919:11;:27;;;188886:61;;;;;;;;;;;;;;;;;;187835:1132;;-1:-1:-1;;186780:3:0;;;;;-1:-1:-1;186694:2288:0;;-1:-1:-1;;186694:2288:0;;-1:-1:-1;;;186540:21:0;;;:23;;;;;;186391:2602;;;164411:1;185577:3423;;;:::o;202703:122::-;202794:23;;202703:122;:::o;194224:170::-;163911:17;:15;:17::i;:::-;-1:-1:-1;;;;;163897:31:0;:10;-1:-1:-1;;;;;163897:31:0;;163930:32;;;;;;;;;;;;;;;;;163889:74;;;;;-1:-1:-1;;;;;163889:74:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;163889:74:0;;194333:53;194361:24;194333:27;:53::i;198109:152::-;198191:7;198218:35;198237:6;198245:7;198218:18;:35::i;202378:120::-;-1:-1:-1;;;;;202464:23:0;202437:7;202464:23;;;:15;:23;;;;;:26;;202378:120::o;195067:103::-;195120:7;195147:15;:4;:13;:15::i;:::-;195140:22;;195067:103;:::o;194540:95::-;194615:11;;-1:-1:-1;;;;;194615:11:0;194540:95;:::o;217020:113::-;217111:9;:14;;;217020:113::o;31773:165::-;31862:7;31889:41;31899:4;22597:1;31918:4;31924:5;31889:9;:41::i;:::-;31882:48;31773:165;-1:-1:-1;;;;31773:165:0:o;219597:291::-;219751:23;;;;219794:20;;;;219847:26;;;;:33;219751:23;;219597:291::o;209592:740::-;209717:25;;;;;;;;;;;;;;;;;209704:11;209696:47;;;;-1:-1:-1;;;;;209696:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;209696:47:0;;209754:48;209780:6;209788:7;209797:4;209754:25;:48::i;:::-;-1:-1:-1;;;;;210018:16:0;:5;:14;:16::i;:::-;-1:-1:-1;;;;;;210018:58:0;;210014:130;;;210093:39;210109:6;210117:7;210126:5;210093:15;:39::i;:::-;210168:6;-1:-1:-1;;;;;210161:55:0;;210176:7;210185:23;210201:6;210185:15;:23::i;:::-;210210:5;210161:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;210161:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;210235:11;;:59;;-1:-1:-1;;;;;210235:11:0;210264:5;210279:4;210286:7;210235:59;:28;:59;:::i;:::-;210296:27;;;;;;;;;;;;;;;;;210227:97;;;;;-1:-1:-1;;;;;210227:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;167808:148:0;167860:17;167915:10;;;;;;;;;-1:-1:-1;;;;;167915:10:0;-1:-1:-1;;;;;167915:30:0;;:32;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;222038:164:0;222114:7;222141:19;:17;:19::i;:::-;-1:-1:-1;;;;;222141:32:0;;222174:19;222141:53;;;;;;;;;;;;;-1:-1:-1;;;;;222141:53:0;-1:-1:-1;;;;;222141:53:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;222141:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;222141:53:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;222141:53:0;;222038:164;-1:-1:-1;;222038:164:0:o;1663:320::-;1796:105;;;-1:-1:-1;;;;;1796:105:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;1796:105:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;1833:17:0;179:29:-1;160:49;;1747:4:0;;1919:56;1949:6;1796:105;1919:21;:56::i;:::-;1912:63;1663:320;-1:-1:-1;;;;;1663:320:0:o;214015:243::-;214079:7;214100:14;214116:17;214137:27;214168:18;214179:6;214168:10;:18::i;:::-;214099:87;;;;;;;214204:46;214230:19;214204:21;214218:6;214204:9;:13;;:21;;;;:::i;:::-;:25;:46;:25;:46;:::i;166206:140::-;166256:15;166307:10;;;;;;;;;-1:-1:-1;;;;;166307:10:0;-1:-1:-1;;;;;166307:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;212260:862:0;212663:12;212659:51;;212692:7;;212659:51;-1:-1:-1;;;;;212744:23:0;;212722:19;212744:23;;;:15;:23;;;;;212778:337;;;;212833:22;;;;:35;;212860:7;212833:35;:26;:35;:::i;:::-;212808:22;;;:60;212778:337;;;212920:5;:22;;;212909:7;:33;;212944:34;;;;;;;;;;;;;;;;;212901:78;;;;;-1:-1:-1;;;;;212901:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;212901:78:0;-1:-1:-1;213070:22:0;;:33;;;;;;;;;-1:-1:-1;;212260:862:0:o;215998:194::-;216081:7;216108:20;216121:6;216108:12;:20::i;:::-;:76;;216183:1;216108:76;;;216159:20;;;;216144:9;;216131:49;;216159:20;216131:23;;:4;;:23;:12;:23;:::i;:::-;:27;:49;:27;:49;:::i;217477:271::-;217685:23;;;;217583:7;;217641:26;;;;-1:-1:-1;;;;;217685:34:0;;;:23;;:34;:55;;217739:1;217685:55;;;217722:14;;217678:62;-1:-1:-1;;;217477:271:0:o;6420:175::-;6547:18;;;;;;;;;;;;;;;;;6480:7;;6512;;;;6538;;;;6530:36;;;;-1:-1:-1;;;;;6530:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;6530:36:0;-1:-1:-1;6586:1:0;6420:175;-1:-1:-1;;;6420:175:0:o;208374:826::-;-1:-1:-1;;;;;208501:23:0;;208479:19;208501:23;;;:15;:23;;;;;;;;;208573:25;;;208640:14;;208706:40;;;;;;;;;;;;;;;;;;;208501:23;;208573:25;;208640:14;208673:31;;;;208665:82;;;;-1:-1:-1;;;;;208665:82:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;208665:82:0;-1:-1:-1;208853:30:0;;;208894:33;;;208940:49;208967:6;208876:7;208984:4;208940:26;:49::i;:::-;-1:-1:-1;209053:8:0;;209041:49;;:4;;209073:1;209063:11;;;;209076:7;;209041:49;:11;:49;:::i;:::-;209141:23;;;;209108:84;;;-1:-1:-1;;;;;209141:23:0;;;209108:84;;;;;;;;;;;;;;;;-1:-1:-1;;;;;209108:84:0;;;;;;;;;;;;;208374:826;;;;;;;:::o;222312:564::-;222415:7;222435:21;222459:22;222474:6;222459:14;:22::i;:::-;-1:-1:-1;;;;;222533:34:0;;222492:38;222533:34;;;:19;:34;;;;;;222435:46;;-1:-1:-1;222580:235:0;;;;222647:43;:30;222682:7;222647:43;:34;:43;:::i;:::-;-1:-1:-1;;;;;222610:34:0;;;;;;:19;:34;;;;;:80;222580:235;;;222760:43;:30;222795:7;222760:43;:34;:43;:::i;:::-;-1:-1:-1;;;;;222723:34:0;;;;;;:19;:34;;;;;:80;222580:235;-1:-1:-1;;;;;;222834:34:0;;;;;:19;:34;;;;;;;222312:564;-1:-1:-1;;;;222312:564:0:o;27333:639::-;27463:12;;27477:24;;;;;;;;;;;;;;;;;;27456:19;;27448:54;;;;-1:-1:-1;;;;;27448:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;27448:54:0;;27596:17;27616:19;27624:4;27630;27616:7;:19::i;:::-;27596:39;;27646:16;27665:9;:57;;27701:21;:9;27715:6;27701:21;:13;:21;:::i;:::-;27665:57;;;27677:21;:9;27691:6;27677:21;:13;:21;:::i;:::-;27646:76;;27733:46;27738:4;22597:1;27757:4;27763:5;27770:8;27733:4;:46::i;:::-;27915:49;27927:4;27933;27939:5;27946:6;27954:9;27915:11;:49::i;142947:1637::-;143008:13;;:::i;:::-;143035:15;143061:23;;:::i;:::-;143095:22;143128:29;;:::i;:::-;143168:22;;:::i;:::-;143201:41;;:::i;:::-;143253:31;;:::i;:::-;143288:14;:12;:14::i;:::-;-1:-1:-1;;;;;143288:24:0;;143313:7;143288:33;;;;;;;;;;;;;-1:-1:-1;;;;;143288:33:0;-1:-1:-1;;;;;143288:33:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;143288:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;143288:33:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;13:3;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;143288:33:0;;;;;;;;-1:-1:-1;143288:33:0;;;;-1:-1:-1;143288:33:0;-1:-1:-1;143288:33:0;;;;-1:-1:-1;143288:33:0;;;;-1:-1:-1;143288:33:0;;;;-1:-1:-1;143288:33:0;;;-1:-1:-1;143334:20:0;;:::i;:::-;143381:198;;;;;;;;-1:-1:-1;;;;;143381:198:0;;;;;143559:8;;;;143381:198;;;;;;143448:8;;143381:198;;;;143481:8;;;;143381:198;;;;143515:8;;;;143381:198;;;;143367:212;;;143610:679;;;;;;;;;;;;143704:15;;-1:-1:-1;;;;;143610:679:0;;;;;;;;;;;143704:12;143760:1;143747:15;;;;-1:-1:-1;;;;;143610:679:0;;;;;143790:12;143803:1;143790:15;;;;;;;;;;;-1:-1:-1;;;;;143610:679:0;;;;;143833:12;143846:1;143833:15;;;;;;;;;;;-1:-1:-1;;;;;143610:679:0;;;;;143883:12;143896:1;143883:15;;;;;;;;;;;-1:-1:-1;;;;;143610:679:0;;;;;143925:5;143931:1;143925:8;;;;;;;;;;;143610:679;;;;;;143972:12;143985:1;143972:15;;;;;;;;;;;-1:-1:-1;;;;;143610:679:0;;;;;144020:12;144033:1;144020:15;;;;;;;;;;;-1:-1:-1;;;;;143610:679:0;;;;;144125:12;144138:1;144125:15;;;;;;;;;;;-1:-1:-1;;;;;143610:679:0;;;;;144074:12;144087:1;144074:15;;;;;;;;;;;-1:-1:-1;;;;;143610:679:0;;;;;144179:23;144203:1;144179:26;;;;;;;;;;;143610:679;;;;144251:23;144275:1;144251:26;;;;;;;;;;;143610:679;;;143592:6;:15;;:697;;;;144318:232;;;;;;;;144364:13;144378:1;144364:16;;;;;;;;;;;144318:232;;;;144417:13;144431:1;144417:16;;;;;;;;;;;144318:232;;;;144470:13;144484:1;144470:16;;;;;;;;;;;144318:232;;;;144522:13;144536:1;144522:16;;;;;;;;;;;144318:232;;144302:13;;;:248;:13;142947:1637;-1:-1:-1;;;;;;;;;142947:1637:0:o;218012:533::-;218082:7;218405:11;218430:23;:21;:23::i;:::-;-1:-1:-1;;;;;218419:34:0;:7;-1:-1:-1;;;;;218419:34:0;;;218405:48;;218471:6;:66;;218513:24;:4;218529:7;218513:24;:15;:24;:::i;:::-;218471:66;;;218480:30;:4;218502:7;218480:30;:21;:30;:::i;5139:460::-;5199:7;5443;5439:48;;-1:-1:-1;5474:1:0;5467:8;;5439:48;5511:7;;;5516:2;5511;:7;:2;5537:6;;;;;:12;5551:18;;;;;;;;;;;;;;;;;5529:41;;;;;-1:-1:-1;;;;;5529:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;6167:177:0;6227:7;6261:2;6255;:8;;6265:19;;;;;;;;;;;;;;;;;6247:38;;;;;-1:-1:-1;;;;;6247:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;6247:38:0;-1:-1:-1;;6308:7:0;;;6167:177::o;46530:152::-;46607:7;45987:4;46634:14;:4;46643;46634:14;:8;:14;:::i;:::-;:40;;;;;;;46530:152;-1:-1:-1;;;46530:152:0:o;145381:147::-;145450:7;145477:14;:12;:14::i;:::-;-1:-1:-1;;;;;145477:34:0;;145512:7;145477:43;;;;;;;;;;;;;-1:-1:-1;;;;;145477:43:0;-1:-1:-1;;;;;145477:43:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;214736:346:0;-1:-1:-1;;;;;214908:23:0;;214795:14;214908:23;;;:15;:23;;;;;214795:14;;;;;;214953:19;214908:23;214953:12;:19::i;:::-;:48;;215000:1;214953:48;;;214988:8;;214975:22;;:4;;:22;:12;:22;:::i;:::-;214944:57;;215055:19;215068:5;215055:12;:19::i;:::-;214736:346;;215012:62;;-1:-1:-1;215012:62:0;;-1:-1:-1;214736:346:0;-1:-1:-1;;;214736:346:0:o;10571:217::-;10632:13;10677:1;10662:5;:12;:16;10658:65;;;-1:-1:-1;10709:1:0;10695:16;;10658:65;-1:-1:-1;10773:4:0;10762:16;10756:23;;10744:37::o;10796:394::-;10877:14;10923:9;10935:2;10923:14;10908:5;:12;:29;10904:134;;;-1:-1:-1;11025:1:0;11018:8;;10904:134;-1:-1:-1;11156:24:0;11083:2;11156:24;11150:31;;11138:45::o;203454:2003::-;203549:13;203565:20;:18;:20::i;:::-;203549:36;;203662:43;203690:6;203698;203662:27;:43::i;:::-;-1:-1:-1;;;;;203745:23:0;;203718:24;203745:23;;;:15;:23;;;;;:40;;;;203823:12;;:41;;203857:7;203823:41;;;203838:16;203823:41;203796:68;;203902:1;203883:16;:20;203905:25;;;;;;;;;;;;;;;;;203875:56;;;;;-1:-1:-1;;;;;203875:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;203875:56:0;-1:-1:-1;203988:31:0;;;;;;;;;;;;;;;;;203950:36;;;;203942:78;;;;-1:-1:-1;;;;;203942:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;203942:78:0;-1:-1:-1;204062:1:0;204053:10;;204074:54;204053:10;204111:16;204074:24;:54::i;:::-;-1:-1:-1;;;;;204161:23:0;;204139:19;204161:23;;;:15;:23;;;;;;204222:32;204243:10;204222:20;:32::i;:::-;204195:59;;204265:24;204292;204309:6;204292:16;:24::i;:::-;204265:51;;204333:19;204346:5;204333:12;:19::i;:::-;204329:769;;;204608:8;;204571:21;;204595:22;;:4;;:22;:12;:22;:::i;:::-;204571:46;-1:-1:-1;204632:24:0;204659:35;204571:46;204677:16;204659:35;:17;:35;:::i;:::-;204632:62;;204737:16;204717;:36;;204755:30;;;;;;;;;;;;;;;;;204709:77;;;;;-1:-1:-1;;;;;204709:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;204709:77:0;-1:-1:-1;204813:8:0;;204801:57;;:4;;204823:10;204835:16;204853:4;204801:57;:11;:57;:::i;:::-;204329:769;;;;;204937:30;;;;;;;;;;;;;;;;;204899:36;;;;204891:77;;;;-1:-1:-1;;;;;204891:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;204891:77:0;-1:-1:-1;204994:41:0;:4;205006:10;205018:16;204994:41;:11;:41;:::i;:::-;204983:52;;;:8;205050:27;;;:17;:27;;;;;:36;;-1:-1:-1;;205050:36:0;-1:-1:-1;;;;;205050:36:0;;;;;204329:769;205110:33;205146:58;205173:6;205181:16;205199:4;205146:26;:58::i;:::-;205110:94;;205252:16;205223:25;:45;;205270:30;;;;;;;;;;;;;;;;;205215:86;;;;;-1:-1:-1;;;;;205215:86:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;205215:86:0;;205314:58;205340:6;205348:16;205366:5;205314:25;:58::i;:::-;205388:61;;;-1:-1:-1;;;;;205388:61:0;;;;;;;;;;-1:-1:-1;;;;;205388:61:0;;;;;;;;;;;;;;;;;;;;;;203454:2003;;;;;;;;;;;:::o;11334:482::-;11437:12;11489:14;11481:5;:22;11466:5;:12;:37;11462:126;;;-1:-1:-1;11564:12:0;;;11574:1;11564:12;;;;;;;;11557:19;;11462:126;11600:24;11637:14;11627:25;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;11627:25:0;87:34:-1;135:17;;-1:-1;11627:25:0;-1:-1:-1;11600:52:0;-1:-1:-1;11680:5:0;11663:117;11699:14;11691:5;:22;11687:1;:26;11663:117;;;11760:5;11766:1;11760:8;;;;;;;;;;;;;;;;11735:11;11751:5;11747:1;:9;11735:22;;;;;;;;;;;:33;;;;;;;;;;-1:-1:-1;11715:3:0;;11663:117;;;-1:-1:-1;11797:11:0;11334:482;-1:-1:-1;;;;11334:482:0:o;165098:110::-;165146:6;165172:8;:6;:8::i;:::-;-1:-1:-1;;;;;165172:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;165172:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;205810:729:0;205899:13;205915:20;:18;:20::i;:::-;205899:36;;206017:43;206045:6;206053;206017:27;:43::i;:::-;-1:-1:-1;;;;;206136:23:0;;206073:17;206136:23;;;:15;:23;;;;;206208:25;;;206261:14;;206102:1;206093:10;;;206136:23;206208:25;206261:27;;206280:7;206261:27;:18;:27;:::i;:::-;206244:44;;206299:23;;;:36;;-1:-1:-1;;206299:36:0;-1:-1:-1;;;;;206299:36:0;;;;;206348:50;206375:6;206383:7;-1:-1:-1;206348:26:0;:50::i;:::-;-1:-1:-1;206421:8:0;;206409:49;;:4;;206431:10;206443:7;206421:8;206409:49;:11;:49;:::i;:::-;206476:55;;;-1:-1:-1;;;;;206476:55:0;;;;;;;;;;;;-1:-1:-1;;;;;206476:55:0;;;;;;;;;;;205810:729;;;;;;:::o;216523:279::-;216609:7;216629:24;216656:23;:21;:23::i;:::-;216629:50;;216697:20;216710:6;216697:12;:20::i;:::-;:97;;216793:1;216697:97;;;216769:20;;;;216735:9;;216720:70;;216769:20;216720:44;;:4;;216746:17;216720:44;:14;:44;:::i;206921:1011::-;-1:-1:-1;;;;;207032:23:0;;207010:19;207032:23;;;:15;:23;;;;;207177;;;;207104:25;;;;-1:-1:-1;;;;;207177:23:0;207316:40;;;:81;;;207370:27;-1:-1:-1;;;;;207360:37:0;:7;-1:-1:-1;;;;;207360:37:0;;207316:81;207312:120;;;207414:7;;;;;207312:120;207473:14;;207680:23;;;;:35;;-1:-1:-1;;207680:35:0;;;207444:26;207726:18;;207755:59;;207781:6;;207473:14;;207755:25;:59::i;:::-;207832:92;;;-1:-1:-1;;;;;207832:92:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;207832:92:0;;;;;;;;;;;;;206921:1011;;;;;;:::o;210631:1251::-;210743:25;;;;;;;;;;;;;;;;;210730:11;210722:47;;;;-1:-1:-1;;;;;210722:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;210722:47:0;;211270:24;211297:23;:21;:23::i;:::-;-1:-1:-1;;;;;211422:23:0;;211391:28;211422:23;;;:15;:23;;;;;;;;:45;;211270:50;;-1:-1:-1;;;;;;211422:45:0;211486:26;;;:71;;;211540:17;-1:-1:-1;;;;;211516:41:0;:21;-1:-1:-1;;;;;211516:41:0;;211486:71;211559:22;;;;;;;;;;;;;;;;;211478:104;;;;;-1:-1:-1;;;;;211478:104:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;211478:104:0;;211595:54;211623:6;211631:17;211595:27;:54::i;:::-;211662:49;211688:6;211696:7;211705:5;211662:25;:49::i;:::-;211736:6;-1:-1:-1;;;;;211727:57:0;;211744:7;211753:23;211769:6;211753:15;:23::i;:::-;211778:5;211727:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;211727:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;211803:11;;:41;;-1:-1:-1;;;;;211803:11:0;211828:6;211836:7;211803:41;:24;:41;:::i;:::-;211846:27;;;;;;;;;;;;;;;;;211795:79;;;;;-1:-1:-1;;;;;211795:79:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;221316:608:0;221392:18;;:::i;:::-;221446:10;;;;221423:13;221495:28;221446:10;221495:20;:28::i;:::-;221468:55;;221543:373;;;;;;;;221594:7;221602:1;221594:10;;;;;;;;;;;;;;;;221543:373;;221631:10;;;;221543:373;;;;-1:-1:-1;;;;;221543:373:0;;;;;;;221701:10;;;;221543:373;;;;;221748:10;;;;221543:373;;;;;221795:10;;;;221543:373;;;;;;221837:40;221631:10;221873:1;221865:10;;;;221837:16;;:40;:20;:40;:::i;:::-;221543:373;;221903:1;221543:373;;;;;221536:380;221316:608;-1:-1:-1;;;;221316:608:0:o;220261:458::-;220333:20;220355:31;220423:288;220462:7;:22;;;220499:7;:17;;;220531:7;:14;;;220560:7;:22;;;220597:7;:28;;;220640:7;:28;;;220683:7;:17;;;220423:4;:24;;:288;;;;;;;;;;:::i;:::-;220399:312;;;;-1:-1:-1;220261:458:0;-1:-1:-1;;220261:458:0:o;165914:115::-;165964:7;165991:10;;;;;;;;;-1:-1:-1;;;;;165991:10:0;-1:-1:-1;;;;;165991:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;213323:456:0;213452:36;;;;;;;;;;;;;;;;;213422:28;213414:75;;;;-1:-1:-1;;;;;213414:75:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;213414:75:0;;213535:41;213552:23;:21;:23::i;:::-;213535:16;:41::i;:::-;213508:24;:68;213578:34;;;;;;;;;;;;;;;;;213500:113;;;;;-1:-1:-1;;;;;213500:113:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;213500:113:0;-1:-1:-1;213660:23:0;;213629:81;;;;;;;;;;;;;;;;;;;;;;;;213721:23;:50;213323:456::o;215388:233::-;-1:-1:-1;;;;;215513:23:0;;215471:7;215513:23;;;:15;:23;;;;;215554:19;215513:23;215554:12;:19::i;:::-;:59;;215612:1;215554:59;;;215591:8;;215576:33;;:4;;215601:7;215576:33;:14;:33;:::i;29912:175::-;29972:7;29992:17;30012:15;30022:4;30012:9;:15::i;:::-;29992:35;;30045:34;30053:4;30059:9;22945:1;30045:7;:34::i;32681:175::-;32786:7;32813:18;;;:10;;;:18;;;;;;;;:24;;;;;;;;:35;;32842:5;32813:35;:28;:35;:::i;2171:378::-;2327:136;;;-1:-1:-1;;;;;2327:136:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;2327:136:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;2364:28:0;179:29:-1;160:49;;2274:4:0;;2481:60;2364:6;2327:136;2481:21;:60::i;:::-;2474:67;2171:378;-1:-1:-1;;;;;;2171:378:0:o;3073:1346::-;3160:4;3177:8;3237:4;3231:11;3668:4;3596:3;3544:9;3538:16;3496:4;3485:9;3481:20;3430:1;3380:5;3322:3;3299:423;3741:14;;3738:2;;3853:14;3941:57;;;;4080:4;4075:189;;;;3846:519;;3941:57;3978:1;3971:8;;3941:57;;4075:189;4243:1;4237:3;4231:10;4228:17;4221:24;;3846:519;;3738:2;-1:-1:-1;4408:3:0;;3073:1346;-1:-1:-1;;;;3073:1346:0:o;31341:140::-;31414:7;31441:32;31449:4;22597:1;31468:4;31441:7;:32::i;37915:163::-;38027:18;;;;:10;;;:18;;;;;;;;:24;;;;;;;;:43;;38056:5;38063:6;38027:43;:28;:43;:::i;34481:1952::-;-1:-1:-1;;34659:4:0;34600:12;34698:15;34708:4;34698:9;:15::i;:::-;34674:39;-1:-1:-1;34759:1:0;34724:1419;34771:13;34762:5;:22;34724:1419;;22409:1;35337:22;;;;;35861:18;;;;35925:17;35945:33;35953:4;35959:5;35861:18;35945:7;:33::i;:::-;35925:53;;35993:16;36012:9;:57;;36048:21;:9;36062:6;36048:21;:13;:21;:::i;:::-;36012:57;;;36024:21;:9;36038:6;36024:21;:13;:21;:::i;:::-;35993:76;;36084:47;36089:4;36095:5;36102:11;36115:5;36122:8;36084:4;:47::i;:::-;-1:-1:-1;;34786:7:0;;34724:1419;;;;36337:9;36336:10;:65;;;;36395:6;36350:41;36358:4;36364:13;36379:11;36350:7;:41::i;:::-;:51;;36336:65;36403:21;;;;;;;;;;;;;;;;;36328:97;;;;;-1:-1:-1;;;;;36328:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;36328:97:0;;34481:1952;;;;;;;;:::o;165372:121::-;165428:6;165454:8;:6;:8::i;:::-;-1:-1:-1;;;;;165454:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;30428:215:0;30504:7;30524:17;30544:30;30562:4;30568:5;30544:17;:30::i;:::-;30524:50;;30592:43;30602:4;30608:9;22945:1;30629:5;30592:9;:43::i;30959:227::-;31041:7;31061:17;31081:30;31099:4;31105:5;31081:17;:30::i;:::-;31061:50;;31129:49;31145:4;31151:9;22945:1;31172:5;31129:15;:49::i;218813:352::-;218905:33;218941:30;218963:7;218941:21;:30::i;:::-;218905:66;-1:-1:-1;218982:29:0;219014:38;218905:66;219044:7;219014:38;:29;:38;:::i;:::-;218982:70;;219096:23;;219071:21;:48;;219121:35;;;;;;;;;;;;;;;;;219063:94;;;;;-1:-1:-1;;;;;219063:94:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;25130:779:0;25449:14;;;;;;;25213:7;;25474:38;25449:4;:14;25506:5;25474:20;:38::i;:::-;25741:10;;25737:144;;25768:43;25773:4;22597:1;25792:3;25797:5;25804:6;25768:4;:43::i;:::-;25826;25838:4;25844:3;25849:5;25856:6;25864:4;25826:11;:43::i;46255:132::-;46318:7;45903:5;46345:23;:4;46354:13;;;46345:23;:8;:23;:::i;48292:1083::-;48657:26;48685:31;48735:11;48748:12;48764:98;48785:4;48791:7;48800:15;48817:21;48840;48764:20;:98::i;:::-;48734:128;;;;48873:25;48901:201;48944:15;48974:10;48999:19;49033:21;49069:3;49087:4;48901:28;:201::i;:::-;48873:229;-1:-1:-1;49145:30:0;:4;48873:229;49167:7;49145:30;:11;:30;:::i;:::-;49216:21;;49196:16;;49239:32;;;;;;;;;;;;;;;;;49115:60;;-1:-1:-1;49115:60:0;;-1:-1:-1;49196:41:0;49188:84;;;;-1:-1:-1;;;;;49188:84:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;49188:84:0;;49311:21;49291:9;:16;:41;49334:32;;;;;;;;;;;;;;;;;49283:84;;;;;-1:-1:-1;;;;;49283:84:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;49283:84:0;;48292:1083;;;;;;;;;;;;;;:::o;33491:117::-;33552:7;33579:21;:4;:11;;:19;:21::i;32162:158::-;32251:7;32278:18;;;:10;;;:18;;;;;;;;:24;;;;;;;;:34;;:32;:34::i;14514:133::-;14586:7;14613:26;14627:4;14633:5;14613:13;:26::i;13405:192::-;13521:19;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;13498:21:0;;;13490:51;;;;-1:-1:-1;;;;;13490:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;13490:51:0;;13552:37;13560:4;13566:5;13581:6;13552:7;:37::i;33823:146::-;33906:7;33933:28;:11;;;33955:5;33933:28;:21;:28;:::i;33239:187::-;33350:7;33377:18;;;:10;;;:18;;;;;;;;:24;;;;;;;;:41;;33412:5;33377:41;:34;:41;:::i;36692:758::-;36791:21;36815:15;36825:4;36815:9;:15::i;:::-;36791:39;;36845;36861:13;36876:7;36845:15;:39::i;:::-;36841:602;;;37245:1;37229:17;;37209;37281:38;37289:4;37229:13;37209:17;37281:7;:38::i;:::-;37261:58;;37334:49;37339:4;37345:9;22945:1;37366:5;37373:9;37334:4;:49::i;:::-;37398:33;:11;;;37414:5;37421:9;37398:33;:15;:33;:::i;50084:627::-;50349:11;;;50421:30;:4;50443:7;50421:30;:21;:30;:::i;:::-;50392:59;-1:-1:-1;50468:66:0;50512:21;50468:39;:15;50392:59;50468:39;:19;:39;:::i;:::-;:43;:66;:43;:66;:::i;:::-;50462:72;-1:-1:-1;50547:25:0;50575:42;:15;50595:21;50575:42;:19;:42;:::i;:::-;50547:70;-1:-1:-1;50635:68:0;50681:21;50635:41;50547:70;50657:18;50635:41;:21;:41;:::i;:68::-;50628:75;;50084:627;;;;;;;;;;:::o;51563:2144::-;51866:16;52184:14;52166:15;:32;52200:29;;;;;;;;;;;;;;;;;52158:72;;;;;-1:-1:-1;;;;;52158:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;52158:72:0;;52241:16;52278:14;52260:15;:32;52241:51;;52400:25;52442:21;52428:36;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;52428:36:0;-1:-1:-1;52400:64:0;-1:-1:-1;52480:24:0;52475:1199;52529:21;52510:16;:40;52475:1199;;;53001:84;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;53001:84:0;;;;;;;52991:95;;;;;53309:44;53344:8;52991:95;53344:8;53328:24;;;;53309:14;;53328:24;;53309:44;:18;:44;:::i;:::-;53280:8;53289:16;53280:26;;;;;;;;;;;;;;;;;:73;53452:16;53435:228;53474:1;53470;:5;:38;;;;;53493:8;53506:1;53502;:5;53493:15;;;;;;;;;;;;;;53479:8;53488:1;53479:11;;;;;;;;;;;;;;:29;53470:38;53435:228;;;53534:11;53548:8;53561:1;53557;:5;53548:15;;;;;;;;;;;;;;53534:29;;53600:8;53609:1;53600:11;;;;;;;;;;;;;;53582:8;53595:1;53591;:5;53582:15;;;;;;;;;;;;;:29;;;;;53644:3;53630:8;53639:1;53630:11;;;;;;;;;;;;;;;;;:17;-1:-1:-1;;;53510:3:0;53435:228;;;-1:-1:-1;;52552:18:0;;52475:1199;;;-1:-1:-1;53691:8:0;51563:2144;-1:-1:-1;;;;;;;;51563:2144:0:o;28658:1119::-;28765:21;28788:23;28854:1;28837:7;:14;:18;28857:27;;;;;;;;;;;;;;;;;28829:56;;;;;-1:-1:-1;;;;;28829:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;28829:56:0;;29032:13;29048:29;29065:4;29071:5;29048:16;:29::i;:::-;29032:45;;29179:1;29171:5;:9;:48;;;;;29192:7;29217:1;29200:7;:14;:18;29192:27;;;;;;;;;;;;;;29184:5;:35;29171:48;29221:26;;;;;;;;;;;;;;;;;29163:85;;;;;-1:-1:-1;;;;;29163:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;29163:85:0;;29317:17;29337:30;29355:4;29361:5;29337:17;:30::i;:::-;29317:50;;29378:32;;:::i;:::-;29413:53;;;;;;;;;-1:-1:-1;;;;;29413:53:0;;;;;;;29433:16;:9;29447:1;29433:16;:13;:16;:::i;:::-;29413:53;;;;22945:1;29413:53;;;;29461:1;29413:53;;;;29464:1;29413:53;;;29378:88;;29597:14;29614:7;:14;29597:31;;29660:6;29646:21;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;29646:21:0;;29639:28;;29701:6;29687:21;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;29687:21:0;;29678:30;;29719:50;29727:4;29733:7;29742:12;29756:4;29762:6;29719:7;:50::i;:::-;28658:1119;;;;;;;;;;:::o;13786:246::-;13885:19;;13848:7;;13919:10;;13915:89;;13961:4;:12;;13983:1;13974:6;:10;13961:24;;;;;;;;;;;;;;;;;:30;-1:-1:-1;;;13961:30:0;;-1:-1:-1;;;;;13961:30:0;;-1:-1:-1;13946:46:0;;-1:-1:-1;13946:46:0;13915:89;-1:-1:-1;14023:1:0;;13786:246;-1:-1:-1;;13786:246:0:o;18431:1576::-;18635:19;;18512:7;;18669:11;18665:52;;18704:1;18697:8;;;;;18665:52;18899:23;;-1:-1:-1;;18865:10:0;;;18899:4;;18865:10;;18899:23;;;;;;;;;;;;;;;:28;-1:-1:-1;;;;;18899:28:0;;;18890:37;;;;18886:115;;18959:4;:12;;18972:9;18959:23;;;;;;;;;;;;;;;;;:29;-1:-1:-1;;;18959:29:0;;-1:-1:-1;;;;;18959:29:0;;-1:-1:-1;18944:45:0;;-1:-1:-1;;18944:45:0;18886:115;19143:4;:12;;19156:1;19143:15;;;;;;;;;;;;;;;;;:20;-1:-1:-1;;;;;19143:20:0;;;19135:28;;;;19131:69;;;19187:1;19180:8;;;;;;19131:69;19294:11;19335:9;19357:591;19371:3;19364:4;:10;19357:591;;;19559:17;;19511:1;19493:10;;;19506:1;19493:14;19492:20;;19478:11;;19559:4;;19492:20;;19559:17;;;;;;;;;;;;;;;19608:15;;19559:17;;-1:-1:-1;;;;;;19608:15:0;;;;19644;;;-1:-1:-1;19640:297:0;;;19686:3;19680:9;;19640:297;;;19723:7;-1:-1:-1;;;;;19715:15:0;:5;-1:-1:-1;;;;;19715:15:0;;19711:226;;;19847:1;19841:3;:7;19834:14;;19711:226;;;-1:-1:-1;19904:16:0;-1:-1:-1;;;19904:16:0;;-1:-1:-1;;;;;19904:16:0;;-1:-1:-1;19889:32:0;;-1:-1:-1;;;;;19889:32:0;19711:226;19357:591;;;;;;19975:4;:12;;19988:3;19975:17;;;;;;;;;;;;;;;;;:23;-1:-1:-1;;;19975:23:0;;-1:-1:-1;;;;;19975:23:0;;18431:1576;-1:-1:-1;;;;;;;18431:1576:0:o;15748:906::-;15853:19;;15887:11;;;:65;;-1:-1:-1;15915:19:0;;-1:-1:-1;;;;;15902:50:0;;;:4;;-1:-1:-1;;15915:23:0;;;15902:37;;;;;;;;;;;;;;;:42;-1:-1:-1;;;;;15902:42:0;:50;15887:65;15883:764;;;16159:25;;;;;;;;;-1:-1:-1;;;;;16159:25:0;;;;;-1:-1:-1;;;;;16159:25:0;;;;;;;;;;27:10:-1;;39:1;23:18;;45:23;;16141:12:0;:44;;;;;;;;;;;;;;;;;;-1:-1:-1;;;16141:44:0;;;;-1:-1:-1;;16141:44:0;;;;;;;;;;;;;15883:764;;;16441:36;16480:4;:12;;16502:1;16493:6;:10;16480:24;;;;;;;;;;;;;;;;;;16536:22;;16560:27;;;;;;;;;;;;;;;;;;;;16480:24;;-1:-1:-1;;;;;;16527:31:0;;;16536:22;;16527:31;16519:69;;;;-1:-1:-1;;;;;16519:69:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;16519:69:0;-1:-1:-1;16603:32:0;;-1:-1:-1;;;;;16603:32:0;;-1:-1:-1;;;16603:32:0;-1:-1:-1;;;;;16603:32:0;;;;;;15748:906;;;;:::o;15093:148::-;15171:7;15198:35;15221:4;15227:5;15198:22;:35::i;43037:815::-;43125:4;;43611:34;:14;22409:1;43611:34;:18;:34;:::i;:::-;-1:-1:-1;;43671:20:0;;43824:14;;43823:21;;;-1:-1:-1;;43037:815:0;;;;:::o;5722:319::-;5782:7;5815:1;5810:2;:6;5818:14;;;;;;;;;;;;;;;;;5802:31;;;;;-1:-1:-1;;;;;5802:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;5802:31:0;;5902:9;5919:2;5914;:7;;;;;;;5722:319;-1:-1:-1;;;;5722:319:0:o;39129:3467::-;39421:13;;;;39381:37;;39421:33;;22409:1;39421:33;:17;:33;:::i;:::-;39381:73;-1:-1:-1;39472:19:0;39467:3122;22358:2;39497:11;:22;39467:3122;;;39635:7;:14;39612:7;:19;;;:37;39608:83;;39670:5;;39608:83;40580:17;;;;40557:20;;40580:67;;40602:44;;;40580:67;:21;:67;:::i;:::-;40557:90;;40662:22;40687:64;40703:4;40709:7;:13;;;40724:12;40738:7;:12;;;40687:15;:64::i;:::-;40662:89;;40990:23;41016:40;41041:14;41016:7;:20;;;:24;;:40;;;;:::i;:::-;40990:66;;41071:29;41103:74;41131:7;41140;:19;;;41161:15;41103:27;:74::i;:::-;41071:106;-1:-1:-1;41293:25:0;;41289:1163;;41562:13;;;;41558:720;;41615:116;41630:7;:19;;;41651:21;41674:12;41688:11;41701:14;41717:13;41615:14;:116::i;:::-;41558:720;;;41780:35;;:::i;:::-;41818:350;;;;;;;;41857:7;:12;;;-1:-1:-1;;;;;41818:350:0;;;;;41912:1;41896:7;:13;;;:17;41818:350;;;;42040:12;41818:350;;;;42079:7;:19;;;41818:350;;;;42125:7;:20;;;41818:350;;;41780:388;;42191:67;42199:4;42205:7;42214:15;42231:11;42244:13;42191:7;:67::i;:::-;41558:720;;42390:19;;;;:46;;42414:21;42390:46;:23;:46;:::i;:::-;42368:19;;;:68;41289:1163;-1:-1:-1;42539:20:0;;;:38;-1:-1:-1;;39521:13:0;;39467:3122;;17259:614;17472:19;;17349:7;;17506:11;17502:52;;17541:1;17534:8;;;;;17502:52;17635:19;;-1:-1:-1;;17582:10:0;;;17566:13;;17635:4;;17582:10;;17635:19;;;;;;;;;;;;;17603:51;;17665:126;17680:1;17672:5;:9;:36;;;;-1:-1:-1;17685:15:0;;-1:-1:-1;;;;;17685:23:0;;;:15;;:23;17672:36;17665:126;;;17760:19;;-1:-1:-1;;17725:7:0;;;;17760:4;;17725:7;;17760:19;;;;;;;;;;;;;17747:32;;17665:126;;;17810:15;;-1:-1:-1;;;;;17810:23:0;;;:15;;:23;:55;;17848:16;;-1:-1:-1;;;17848:16:0;;-1:-1:-1;;;;;17848:16:0;17810:55;;;17836:1;17803:62;17259:614;-1:-1:-1;;;;;;17259:614:0:o;44313:388::-;44443:7;44550:12;44573:87;44584:7;:14;44580:1;:18;:48;;;;;44615:13;44602:7;44610:1;44602:10;;;;;;;;;;;;;;:26;44580:48;44573:87;;;44645:3;;44573:87;;;44677:16;;;;;44313:388;-1:-1:-1;;;44313:388:0:o;45323:403::-;45583:9;45578:141;45602:6;45598:1;:10;45578:141;;;45655:4;45630:11;45650:1;45642:5;:9;45630:22;;;;;;;;;;;;;:29;;;;;45701:6;45674:13;45696:1;45688:5;:9;45674:24;;;;;;;;;;;;;;;;;:33;45610:3;;45578:141;;170956:51923;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;170956:51923:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;170956:51923:0;;;-1:-1:-1;;170956:51923:0:o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;170956:51923:0;;;-1:-1:-1;;170956:51923:0:o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;170956:51923:0;;;-1:-1:-1;;170956:51923:0:o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;170956:51923:0;;;-1:-1:-1;;170956:51923:0:o;:::-;;;;;;;;;;-1:-1:-1;;;;;170956:51923:0;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;-1:-1:-1;;;;;170956:51923:0;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;170956:51923:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;24698:156::-;24751:61;24810:1;24751:11;;;;23110:1;;24751:61;:15;:61;:::i;:::-;22945:1;24823:23;;24698:156::o
Swarm Source
bzzr://e57bffe1a1fdbddc43338eb47739430057a11db435c000010b8722ae74145e92
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.