More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,610 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Unstake | 20401344 | 182 days ago | IN | 0 ETH | 0.00056862 | ||||
Deactivate | 20401213 | 182 days ago | IN | 0 ETH | 0.00010028 | ||||
Deactivate | 20401209 | 182 days ago | IN | 0 ETH | 0.00053209 | ||||
Unstake | 19983722 | 240 days ago | IN | 0 ETH | 0.0044819 | ||||
Deactivate | 19982680 | 240 days ago | IN | 0 ETH | 0.0024013 | ||||
Unstake | 19651210 | 287 days ago | IN | 0 ETH | 0.00163279 | ||||
Deactivate | 19646096 | 287 days ago | IN | 0 ETH | 0.00248532 | ||||
Unstake | 18781436 | 409 days ago | IN | 0 ETH | 0.008537 | ||||
Deactivate | 18778592 | 409 days ago | IN | 0 ETH | 0.01646805 | ||||
Deactivate | 18746741 | 413 days ago | IN | 0 ETH | 0.00119068 | ||||
Unstake | 17399401 | 602 days ago | IN | 0 ETH | 0.00506136 | ||||
Deactivate | 17397013 | 603 days ago | IN | 0 ETH | 0.00567045 | ||||
Unstake | 14391277 | 1047 days ago | IN | 0 ETH | 0.00214055 | ||||
Unstake | 14332120 | 1056 days ago | IN | 0 ETH | 0.00397908 | ||||
Unstake | 14199770 | 1077 days ago | IN | 0 ETH | 0.0108049 | ||||
Deactivate | 14194624 | 1078 days ago | IN | 0 ETH | 0.01033119 | ||||
Unstake | 14088766 | 1094 days ago | IN | 0 ETH | 0.02788295 | ||||
Deactivate | 14082478 | 1095 days ago | IN | 0 ETH | 0.04145903 | ||||
Unstake | 14056462 | 1099 days ago | IN | 0 ETH | 0.02080048 | ||||
Deactivate | 14055918 | 1099 days ago | IN | 0 ETH | 0.02318082 | ||||
Unstake | 14042771 | 1101 days ago | IN | 0 ETH | 0.01693328 | ||||
Unstake | 14035265 | 1102 days ago | IN | 0 ETH | 0.01191462 | ||||
Deactivate | 14031045 | 1103 days ago | IN | 0 ETH | 0.03068242 | ||||
Deactivate | 14017598 | 1105 days ago | IN | 0 ETH | 0.02075771 | ||||
Unstake | 14017533 | 1105 days ago | IN | 0 ETH | 0.0185217 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
JurorsRegistry
Compiler Version
v0.5.8+commit.23d335f2
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-02-07 */ /** * Commit sha: 057b118bce7af86318eb522112350f950e9b7834 * GitHub repository: https://github.com/aragon/aragon-court * Tool used for the deploy: https://github.com/aragon/aragon-network-deploy **/ // File: contracts/lib/os/ERC20.sol // Brought from https://github.com/aragon/aragonOS/blob/v4.3.0/contracts/lib/token/ERC20.sol // Adapted to use pragma ^0.5.8 and satisfy our linter rules pragma solidity ^0.5.8; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 { function totalSupply() public view returns (uint256); function balanceOf(address _who) public view returns (uint256); function allowance(address _owner, address _spender) public view returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); function transferFrom(address _from, address _to, uint256 _value) public returns (bool); event Transfer( address indexed from, address indexed to, uint256 value ); event Approval( address indexed owner, address indexed spender, uint256 value ); } // File: contracts/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)) } } } // 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) function isValid(uint16 _pct) internal pure returns (bool) { return _pct <= PCT_BASE; } 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 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 */ function getTerm(uint64 _termId) external view returns (uint64 startTime, uint64 randomnessBN, bytes32 randomness); /** * @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); } // 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 } // 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) 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; } /** * @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 */ function getTerm(uint64 _termId) external view returns (uint64 startTime, uint64 randomnessBN, bytes32 randomness) { Term storage term = terms[_termId]; return (term.startTime, term.randomnessBN, term.randomness); } /** * @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 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]; _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; } 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); } } // 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 roundStateDurations Array containing the durations in terms of the different phases of a dispute: * 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 * @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 roundParams Array containing params for rounds: * 0. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 1. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 2. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * @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 minActiveBalance Minimum amount of tokens jurors have to activate to participate in the Court */ function getConfig(uint64 _termId) external view returns ( ERC20 feeToken, uint256[3] memory fees, uint64[5] memory roundStateDurations, uint16[2] memory pcts, uint64[4] memory roundParams, uint256[2] memory appealCollateralParams, uint256 minActiveBalance ); /** * @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 uint256 minActiveBalance; // Minimum amount of tokens jurors have to activate to participate in the Court } 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 { 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 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_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"; // 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 _roundStateDurations Array containing the durations in terms of the different phases of a dispute: * 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 * @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 _roundParams Array containing params for rounds: * 0. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 1. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 2. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 3. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @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 _minActiveBalance Minimum amount of juror tokens that can be activated */ constructor( ERC20 _feeToken, uint256[3] memory _fees, uint64[5] memory _roundStateDurations, uint16[2] memory _pcts, uint64[4] memory _roundParams, uint256[2] memory _appealCollateralParams, uint256 _minActiveBalance ) public { // Leave config at index 0 empty for non-scheduled config changes configs.length = 1; _setConfig( 0, 0, _feeToken, _fees, _roundStateDurations, _pcts, _roundParams, _appealCollateralParams, _minActiveBalance ); } /** * @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 roundStateDurations Array containing the durations in terms of the different phases of a dispute: * 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 * @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 roundParams Array containing params for rounds: * 0. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 1. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 2. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * @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 minActiveBalance Minimum amount of tokens jurors have to activate to participate in the Court */ function getConfig(uint64 _termId) external view returns ( ERC20 feeToken, uint256[3] memory fees, uint64[5] memory roundStateDurations, uint16[2] memory pcts, uint64[4] memory roundParams, uint256[2] memory appealCollateralParams, uint256 minActiveBalance ); /** * @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 _roundStateDurations Array containing the durations in terms of the different phases of a dispute: * 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 * @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 _roundParams Array containing params for rounds: * 0. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 1. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 2. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 3. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @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 _minActiveBalance Minimum amount of juror tokens that can be activated */ function _setConfig( uint64 _termId, uint64 _fromTermId, ERC20 _feeToken, uint256[3] memory _fees, uint64[5] memory _roundStateDurations, uint16[2] memory _pcts, uint64[4] memory _roundParams, uint256[2] memory _appealCollateralParams, uint256 _minActiveBalance ) 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); // 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[0] > 0, ERROR_BAD_INITIAL_JURORS_NUMBER); // Prevent that further rounds have zero jurors require(_roundParams[1] > 0, ERROR_BAD_APPEAL_STEP_FACTOR); // Make sure the max number of appeals allowed does not reach the limit uint256 _maxRegularAppealRounds = _roundParams[2]; 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 < _roundStateDurations.length; i++) { require(_roundStateDurations[i] > 0 && _roundStateDurations[i] < MAX_ADJ_STATE_DURATION, ERROR_LARGE_ROUND_PHASE_DURATION); } // Make sure min active balance is not zero require(_minActiveBalance > 0, ERROR_ZERO_MIN_ACTIVE_BALANCE); // 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({ evidenceTerms: _roundStateDurations[0], commitTerms: _roundStateDurations[1], revealTerms: _roundStateDurations[2], appealTerms: _roundStateDurations[3], appealConfirmTerms: _roundStateDurations[4], penaltyPct: _pcts[0], firstRoundJurorsNumber: _roundParams[0], appealStepFactor: _roundParams[1], maxRegularAppealRounds: _maxRegularAppealRounds, finalRoundLockTerms: _roundParams[3], appealCollateralFactor: _appealCollateralParams[0], appealConfirmCollateralFactor: _appealCollateralParams[1] }); config.minActiveBalance = _minActiveBalance; 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 roundStateDurations Array containing the durations in terms of the different phases of a dispute: * 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 * @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 roundParams Array containing params for rounds: * 0. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 1. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 2. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 3. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @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 minActiveBalance Minimum amount of juror tokens that can be activated */ function _getConfigAt(uint64 _termId, uint64 _lastEnsuredTermId) internal view returns ( ERC20 feeToken, uint256[3] memory fees, uint64[5] memory roundStateDurations, uint16[2] memory pcts, uint64[4] memory roundParams, uint256[2] memory appealCollateralParams, uint256 minActiveBalance ) { 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; roundStateDurations = [ disputesConfig.evidenceTerms, disputesConfig.commitTerms, disputesConfig.revealTerms, disputesConfig.appealTerms, disputesConfig.appealConfirmTerms ]; pcts = [disputesConfig.penaltyPct, feesConfig.finalRoundReduction]; roundParams = [ disputesConfig.firstRoundJurorsNumber, disputesConfig.appealStepFactor, uint64(disputesConfig.maxRegularAppealRounds), disputesConfig.finalRoundLockTerms ]; appealCollateralParams = [disputesConfig.appealCollateralFactor, disputesConfig.appealConfirmCollateralFactor]; minActiveBalance = config.minActiveBalance; } /** * @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.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; /** * @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 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 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 modules governor */ modifier onlyConfigGovernor { require(msg.sender == governor.config, 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. _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 _roundStateDurations Array containing the durations in terms of the different phases of a dispute: * 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 * @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 _roundParams Array containing params for rounds: * 0. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 1. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 2. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 3. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @param _appealCollateralParams Array containing params for appeal collateral: * 1. appealCollateralFactor Permyriad multiple of dispute fees required to appeal a preliminary ruling * 2. appealConfirmCollateralFactor Permyriad multiple of dispute fees required to confirm appeal * @param _minActiveBalance Minimum amount of juror tokens that can be activated */ constructor( uint64[2] memory _termParams, address[3] memory _governors, ERC20 _feeToken, uint256[3] memory _fees, uint64[5] memory _roundStateDurations, uint16[2] memory _pcts, uint64[4] memory _roundParams, uint256[2] memory _appealCollateralParams, uint256 _minActiveBalance ) public CourtClock(_termParams) CourtConfig(_feeToken, _fees, _roundStateDurations, _pcts, _roundParams, _appealCollateralParams, _minActiveBalance) { _setFundsGovernor(_governors[0]); _setConfigGovernor(_governors[1]); _setModulesGovernor(_governors[2]); } /** * @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 _roundStateDurations Array containing the durations in terms of the different phases of a dispute: * 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 * @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 _roundParams Array containing params for rounds: * 0. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 1. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 2. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 3. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @param _appealCollateralParams Array containing params for appeal collateral: * 1. appealCollateralFactor Permyriad multiple of dispute fees required to appeal a preliminary ruling * 2. appealConfirmCollateralFactor Permyriad multiple of dispute fees required to confirm appeal * @param _minActiveBalance Minimum amount of juror tokens that can be activated */ function setConfig( uint64 _fromTermId, ERC20 _feeToken, uint256[3] calldata _fees, uint64[5] calldata _roundStateDurations, uint16[2] calldata _pcts, uint64[4] calldata _roundParams, uint256[2] calldata _appealCollateralParams, uint256 _minActiveBalance ) external onlyConfigGovernor { uint64 currentTermId = _ensureCurrentTerm(); _setConfig( currentTermId, _fromTermId, _feeToken, _fees, _roundStateDurations, _pcts, _roundParams, _appealCollateralParams, _minActiveBalance ); } /** * @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 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 roundStateDurations Array containing the durations in terms of the different phases of a dispute: * 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 * @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 roundParams Array containing params for rounds: * 0. firstRoundJurorsNumber Number of jurors to be drafted for the first round of disputes * 1. appealStepFactor Increasing factor for the number of jurors of each round of a dispute * 2. maxRegularAppealRounds Number of regular appeal rounds before the final round is triggered * 3. finalRoundLockTerms Number of terms that a coherent juror in a final round is disallowed to withdraw (to prevent 51% attacks) * @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 */ function getConfig(uint64 _termId) external view returns ( ERC20 feeToken, uint256[3] memory fees, uint64[5] memory roundStateDurations, uint16[2] memory pcts, uint64[4] memory roundParams, uint256[2] memory appealCollateralParams, uint256 minActiveBalance ) { 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 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 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 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 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, uint64[5] memory _roundStateDurations, uint16[2] memory _pcts, uint64[4] memory _roundParams, uint256[2] memory _appealCollateralParams, uint256 _minActiveBalance) = _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({ evidenceTerms: _roundStateDurations[0], commitTerms: _roundStateDurations[1], revealTerms: _roundStateDurations[2], appealTerms: _roundStateDurations[3], appealConfirmTerms: _roundStateDurations[4], penaltyPct: _pcts[0], firstRoundJurorsNumber: _roundParams[0], appealStepFactor: _roundParams[1], maxRegularAppealRounds: _roundParams[2], finalRoundLockTerms: _roundParams[3], appealCollateralFactor: _appealCollateralParams[0], appealConfirmCollateralFactor: _appealCollateralParams[1] }); config.minActiveBalance = _minActiveBalance; 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/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 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; /** * @dev Execute the Arbitrable associated to a dispute based on its final ruling * @param _disputeId Identification number of the dispute to be executed */ function executeRuling(uint256 _disputeId) external; /** * @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); /** * @dev Tell the subscription fees information for a subscriber to be up-to-date * @param _subscriber Address of the account paying the subscription fees for * @return recipient Address where the corresponding subscriptions fees must be transferred to * @return feeToken ERC20 token used for the subscription fees * @return feeAmount Total amount of fees that must be allowed to the recipient */ function getSubscriptionFees(address _subscriber) external view returns (address recipient, ERC20 feeToken, uint256 feeAmount); } // File: contracts/standards/ERC165.sol pragma solidity ^0.5.8; interface ERC165 { /** * @dev Query if a contract implements a certain interface * @param _interfaceId The interface identifier being queried, as specified in ERC-165 * @return True if the contract implements the requested interface and if its not 0xffffffff, false otherwise */ function supportsInterface(bytes4 _interfaceId) external pure returns (bool); } // File: contracts/arbitration/IArbitrable.sol pragma solidity ^0.5.8; contract IArbitrable is ERC165 { bytes4 internal constant ERC165_INTERFACE_ID = bytes4(0x01ffc9a7); bytes4 internal constant ARBITRABLE_INTERFACE_ID = bytes4(0x88f3ee69); /** * @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); /** * @dev Emitted when new evidence is submitted for the IArbitrable instance's 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 * @param finished Whether or not the submitter has finished submitting evidence */ event EvidenceSubmitted(uint256 indexed disputeId, address indexed submitter, bytes evidence, bool finished); /** * @dev Submit evidence for a dispute * @param _disputeId Id of the dispute in the Court * @param _evidence Data submitted for the evidence related to the dispute * @param _finished Whether or not the submitter has finished submitting evidence */ function submitEvidence(uint256 _disputeId, bytes calldata _evidence, bool _finished) external; /** * @dev Give a ruling for a certain dispute, the account calling it must have rights to rule on the contract * @param _disputeId Identification number of the dispute to be ruled * @param _ruling Ruling given by the arbitrator, where 0 is reserved for "refused to make a decision" */ function rule(uint256 _disputeId, uint256 _ruling) external; /** * @dev ERC165 - Query if a contract implements a certain interface * @param _interfaceId The interface identifier being queried, as specified in ERC-165 * @return True if this contract supports the given interface, false otherwise */ function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { return _interfaceId == ARBITRABLE_INTERFACE_ID || _interfaceId == ERC165_INTERFACE_ID; } } // 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 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/subscriptions/ISubscriptions.sol pragma solidity ^0.5.8; interface ISubscriptions { /** * @dev Tell whether a certain subscriber has paid all the fees up to current period or not * @param _subscriber Address of subscriber being checked * @return True if subscriber has paid all the fees up to current period, false otherwise */ function isUpToDate(address _subscriber) external view returns (bool); /** * @dev Tell the minimum amount of fees to pay and resulting last paid period for a given subscriber in order to be up-to-date * @param _subscriber Address of the subscriber willing to pay * @return feeToken ERC20 token used for the subscription fees * @return amountToPay Amount of subscription fee tokens to be paid * @return newLastPeriodId Identification number of the resulting last paid period */ function getOwedFeesDetails(address _subscriber) external view returns (ERC20, uint256, uint256); } // 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 Subscriptions module implementation from the controller * @return Address of the Subscriptions module implementation */ function _subscriptions() internal view returns (ISubscriptions) { return ISubscriptions(controller.getSubscriptions()); } /** * @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/registry/JurorsRegistry.sol pragma solidity ^0.5.8; contract JurorsRegistry is ControlledRecoverable, IJurorsRegistry, ERC900, ApproveAndCallFallBack { 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_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_EXCEEDED = "JR_TOTAL_ACTIVE_BALANCE_EXCEEDED"; string private constant ERROR_WITHDRAWALS_LOCK = "JR_WITHDRAWALS_LOCK"; // Address that will be used to burn juror tokens address internal constant BURN_ACCOUNT = address(0x000000000000000000000000000000000000dEaD); // 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; 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 _jurorToken Address of the ERC20 token to be used as juror token for the registry * @param _totalActiveBalanceLimit Maximum amount of total active balance that can be held in the registry */ constructor(Controller _controller, ERC20 _jurorToken, uint256 _totalActiveBalanceLimit) ControlledRecoverable(_controller) public { // No need to explicitly call `Controlled` constructor since `ControlledRecoverable` is already doing it require(isContract(address(_jurorToken)), ERROR_NOT_CONTRACT); jurorsToken = _jurorToken; _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); } /** * @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); 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); } 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 * @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 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); 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); require(activeBalance.add(amountToActivate) >= 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; } _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; 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; // 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); 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 }); } }
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":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":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":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":"_jurorToken","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
60806040523480156200001157600080fd5b50604051606080620051df833981018060405260608110156200003357600080fd5b50805160208083015160409093015191929190839081906200005b9082906200027f811b901c565b6040518060400160405280601b81526020017f4354445f434f4e54524f4c4c45525f4e4f545f434f4e545241435400000000008152509062000138576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620000fc578181015183820152602001620000e2565b50505050905090810190601f1680156200012a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600080546001600160a01b0319166001600160a01b0392909216919091179055506200016c826200027f602090811b901c565b6040518060400160405280600f81526020017f4a525f4e4f545f434f4e54524143540000000000000000000000000000000000815250906200020b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000fc578181015183820152602001620000e2565b50600280546001600160a01b0319166001600160a01b0384161790556200023981620002a4602090811b901c565b6200025060056200038460201b620045e71760201c565b6200026e6000806005620003ad60201b6200359c179092919060201c565b156200027657fe5b50505062000b9f565b60006001600160a01b03821662000299575060006200029f565b50803b15155b919050565b60408051808201909152601d81527f4a525f4241445f544f54414c5f4143544956455f42414c5f4c494d495400000060208201528162000341576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000fc578181015183820152602001620000e2565b50600154604080519182526020820183905280517f9ce60e2304bd08c7c9e6da0e10912e44f85fd9e2ee71c1842132f12146c586c89281900390910190a1600155565b620003a7600080600101836001016200040760201b6200379c179092919060201c565b60009055565b8254600181018455600090620003cc858286620004c7602090811b901c565b8215620003ff57620003e98560008387876200054e60201b60201c565b620003ff8582868660016200058860201b60201c565b949350505050565b60408051808201909152601881527f434845434b504f494e545f56414c55455f544f4f5f424947000000000000000060208201526001600160c01b03821115620004ae576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000fc578181015183820152602001620000e2565b50620004c2838383620006ff60201b60201c565b505050565b6000620004da84620008b260201b60201c565b9050620004ee8184620008d360201b60201c565b1562000548576001810160006200050e86848362000903602090811b901c565b9050620005268683600087856200054e60201b60201c565b620005458483886001016200040760201b6200379c179092919060201c565b50505b50505050565b6000848152600286016020908152604080832086845282529091206200058191849084906200379c62000407821b17901c565b5050505050565b600019846000620005a088620008b2602090811b901c565b905060015b8181116200063457600484901b935083831692506000620005ce8a83866200090360201b60201c565b9050600086620005f857620005f288836200093160201b62002c2e1790919060201c565b62000612565b620006128883620009dd60201b6200224b1790919060201c565b9050620006298b84878c856200054e60201b60201c565b5050600101620005a5565b5083158062000655575084620006528983856200090360201b60201c565b10155b6040518060400160405280601881526020017f53554d5f545245455f5550444154455f4f564552464c4f57000000000000000081525090620006f4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000fc578181015183820152602001620000e2565b505050505050505050565b82548015806200073f575083546001600160401b03841690859060001981019081106200072857fe5b6000918252602090912001546001600160401b0316105b15620007b557604080518082019091526001600160401b0380851682526001600160c01b0380851660208085019182528854600181018a5560008a815291909120945194018054915190921668010000000000000000029383166001600160401b03199091161790911691909117905562000548565b6000846000016001830381548110620007ca57fe5b6000918252602091829020018054604080518082019091528381527f434845434b504f494e545f43414e4e4f545f4144445f504153545f56414c5545938101939093529092506001600160401b0386811691161462000886576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000fc578181015183820152602001620000e2565b5080546001600160c01b03841668010000000000000000026001600160401b0390911617905550505050565b6000620008cd8260010162000a8c60201b62003dfe1760201c565b92915050565b600080620008f160048562000adf60201b620038d71790919060201c565b600019901b8316151591505092915050565b6000828152600284016020908152604080832084845282528220620003ff9162003dfe62000a8c821b17901c565b6000828211156040518060400160405280601281526020017f4d4154485f5355425f554e444552464c4f57000000000000000000000000000081525090620009d6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000fc578181015183820152602001620000e2565b5050900390565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f570000000000000000000000000000006020820152600090838301908482101562000a84576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000fc578181015183820152602001620000e2565b509392505050565b8054600090801562000ad65782600001600182038154811062000aab57fe5b6000918252602090912001546801000000000000000090046001600160c01b031691506200029f9050565b50600092915050565b60008262000af057506000620008cd565b8282028284828162000afe57fe5b04146040518060400160405280601181526020017f4d4154485f4d554c5f4f564552464c4f570000000000000000000000000000008152509062000a84576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315620000fc578181015183820152602001620000e2565b6146308062000baf6000396000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c8063916b9bef11610104578063c8fd6ed0116100a2578063e9e67d6711610071578063e9e67d67146108c7578063f01e7d03146108fd578063f590e92314610923578063fc0c546a1461092b576101da565b8063c8fd6ed0146107b4578063d903bcf41461082b578063dbbd85a6146108a2578063e67a81f4146108aa576101da565b8063af7a9f40116100de578063af7a9f40146105f9578063af8b9d0f1461063c578063b260c42a14610672578063c67106f51461068f576101da565b8063916b9bef1461059057806396a705c1146105ad578063ac8fcfc0146105d3576101da565b8063605da1b21161017c57806370a082311161014b57806370a08231146104ac578063817b1cd2146104d25780638e127793146104da5780638f4ffcb114610501576101da565b8063605da1b2146103ef5780636d1b229d1461043f5780636d6cc6841461045c5780637033e4a6146104a4576101da565b806324ae6a27116101b857806324ae6a27146103395780633018205f146103675780634b341aed1461038b5780634d7edc15146103c3576101da565b8063082b4235146101df5780630e89439b1461023b5780630ef96356146102b4575b600080fd5b610215600480360360408110156101f557600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff16610933565b604080519485526020850193909352838301919091526060830152519081900360800190f35b6102b26004803603604081101561025157600080fd5b8135919081019060408101602082013564010000000081111561027357600080fd5b82018360208201111561028557600080fd5b803590602001918460018302840111640100000000831117156102a757600080fd5b509092509050610993565b005b6102b2600480360360608110156102ca57600080fd5b6001600160a01b03823516916020810135918101906060810160408201356401000000008111156102fa57600080fd5b82018360208201111561030c57600080fd5b8035906020019184600183028401116401000000008311171561032e57600080fd5b5090925090506109da565b6102b26004803603604081101561034f57600080fd5b506001600160a01b0381358116916020013516610a22565b61036f610d6c565b604080516001600160a01b039092168252519081900360200190f35b6103b1600480360360208110156103a157600080fd5b50356001600160a01b0316610d7b565b60408051918252519081900360200190f35b6102b2600480360360408110156103d957600080fd5b506001600160a01b038135169060200135610d8e565b61042b6004803603606081101561040557600080fd5b5080356001600160a01b0316906020810135906040013567ffffffffffffffff16610e86565b604080519115158252519081900360200190f35b6102b26004803603602081101561045557600080fd5b5035611024565b6104826004803603602081101561047257600080fd5b50356001600160a01b0316611111565b6040805192835267ffffffffffffffff90911660208301528051918290030190f35b61042b611143565b610215600480360360208110156104c257600080fd5b50356001600160a01b0316611148565b6103b1611166565b6103b1600480360360208110156104f057600080fd5b503567ffffffffffffffff166111fb565b6102b26004803603608081101561051757600080fd5b6001600160a01b03823581169260208101359260408201359092169181019060808101606082013564010000000081111561055157600080fd5b82018360208201111561056357600080fd5b8035906020019184600183028401116401000000008311171561058557600080fd5b509092509050611206565b6102b2600480360360208110156105a657600080fd5b50356112fa565b6103b1600480360360208110156105c357600080fd5b50356001600160a01b03166114fa565b6102b2600480360360208110156105e957600080fd5b50356001600160a01b031661151b565b61061f6004803603602081101561060f57600080fd5b50356001600160a01b0316611531565b6040805167ffffffffffffffff9092168252519081900360200190f35b6102b26004803603604081101561065257600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff1661155a565b6102b26004803603602081101561068857600080fd5b503561163b565b6103b1600480360360808110156106a557600080fd5b67ffffffffffffffff82351691908101906040810160208201356401000000008111156106d157600080fd5b8201836020820111156106e357600080fd5b8035906020019184602083028401116401000000008311171561070557600080fd5b91939092909160208101903564010000000081111561072357600080fd5b82018360208201111561073557600080fd5b8035906020019184602083028401116401000000008311171561075757600080fd5b91939092909160208101903564010000000081111561077557600080fd5b82018360208201111561078757600080fd5b803590602001918460208302840111640100000000831117156107a957600080fd5b509092509050611646565b6102b2600480360360408110156107ca57600080fd5b813591908101906040810160208201356401000000008111156107ec57600080fd5b8201836020820111156107fe57600080fd5b8035906020019184600183028401116401000000008311171561082057600080fd5b509092509050611953565b610847600480360360e081101561084157600080fd5b50611994565b6040518080602001838152602001828103825284818151815260200191508051906020019060200280838360005b8381101561088d578181015183820152602001610875565b50505050905001935050505060405180910390f35b6103b1611c67565b6102b2600480360360208110156108c057600080fd5b5035611c6d565b6103b1600480360360408110156108dd57600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff16611d18565b6103b16004803603602081101561091357600080fd5b50356001600160a01b0316611d2d565b6103b1611d48565b61036f611d59565b6001600160a01b038216600090815260036020526040812081908190819061095a81611d68565b61096557600061097a565b805461097a906005908863ffffffff611d6e16565b945061098581611d85565b969991985096509350505050565b6109d533338585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d9992505050565b505050565b610a1c33858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d9992505050565b50505050565b6000809054906101000a90046001600160a01b03166001600160a01b0316633c28e88b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a6f57600080fd5b505afa158015610a83573d6000803e3d6000fd5b505050506040513d6020811015610a9957600080fd5b505160408051808201909152601d81527f4354445f53454e4445525f4e4f545f46554e44535f474f5645524e4f520000006020820152906001600160a01b03163314610b6657604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610b2b578181015183820152602001610b13565b50505050905090810190601f168015610b585780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290516000916001600160a01b038516916370a0823191602480820192602092909190829003018186803b158015610bca57600080fd5b505afa158015610bde573d6000803e3d6000fd5b505050506040513d6020811015610bf457600080fd5b505160408051808201909152601e81527f4354445f494e53554646494349454e545f5245434f5645525f46554e44530000602082015290915081610c7c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50610c976001600160a01b038416838363ffffffff611fe416565b6040518060400160405280601e81526020017f4354445f5245434f5645525f544f4b454e5f46554e44535f4641494c4544000081525090610d1c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50604080516001600160a01b0380861682528416602082015280820183905290517f724139fea3954691c2c1ee02b3be6be1763b32ec84841f1acad6d3a18695ba0d9181900360600190a1505050565b6000546001600160a01b031690565b6000610d868261206f565b90505b919050565b610d966120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090610e2f57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b508015610e8257610e42828260016120f7565b6040805182815290516001600160a01b038416917fbfbd6786419e534c0af90164d33c027ddc81c4541f1047d00bb286d5d4dfe8a7919081900360200190a25b5050565b6000610e906120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090610f2957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5082610f375750600161101d565b6001600160a01b03841660009081526003602052604081206001840191610f5d826121dc565b90506000610f6b838561221c565b90506000610f7f838363ffffffff61224b16565b905080881115610f975760009550505050505061101d565b82881115610faf57828803610fad8a828a6122e0565b505b8354610fc790600590878b600063ffffffff61241516565b6040805189815267ffffffffffffffff8716602082015281516001600160a01b038c16927f3b522789764bf3f50da1a4e79a6b330fd1ae121df88d89259fa73b55e1e9e360928290030190a26001955050505050505b9392505050565b61102c6120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c450000815250906110c557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50801561110e576110da61dead8260016120f7565b6040805182815290517fef08526ce447c7a59448d28b89b25b9be13b2ae0293946c9cf27123c8e71a3769181900360200190a15b50565b6001600160a01b0381166000908152600360205260409020600481015460059091015467ffffffffffffffff16915091565b600090565b600080600080611157856124f4565b93509350935093509193509193565b600254604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156111ca57600080fd5b505afa1580156111de573d6000803e3d6000fd5b505050506040513d60208110156111f457600080fd5b5051905090565b6000610d8682612553565b336001600160a01b03841614801561122b57506002546001600160a01b038481169116145b6040518060400160405280601c81526020017f4a525f544f4b454e5f415050524f56455f4e4f545f414c4c4f57454400000000815250906112b057604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506112f385868685858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d9992505050565b5050505050565b60006113046125a3565b33600090815260036020526040812091925061131f826121dc565b90506000841561132f5784611331565b815b9050600081116040518060400160405280601681526020017f4a525f494e56414c49445f5a45524f5f414d4f554e5400000000000000000000815250906113bc57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060408051808201909152601e81527f4a525f494e56414c49445f444541435449564154494f4e5f414d4f554e54000060208201528282111561144357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b508082036000611452866125fb565b90508115806114615750808210155b6040518060400160405280601e81526020017f4a525f494e56414c49445f444541435449564154494f4e5f414d4f554e540000815250906114e657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506114f1338461268e565b50505050505050565b6001600160a01b038116600090815260036020526040812061101d81612761565b60006115256125a3565b9050610e8282826127a1565b6001600160a01b03166000908152600360208190526040909120015467ffffffffffffffff1690565b6115626120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c450000815250906115fb57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506001600160a01b0391909116600090815260036020819052604090912001805467ffffffffffffffff191667ffffffffffffffff909216919091179055565b61110e338233612880565b60006116506120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c450000815250906116e957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060408051808201909152601d81527f4a525f494e56414c49445f4c4f434b45445f414d4f554e54535f4c454e000000602082015286851461176f57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060408051808201909152601e81527f4a525f494e56414c49445f52455741524445445f4a55524f52535f4c454e000060208201528683146117f557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50600188016000805b8881101561194557600088888381811061181457fe5b90506020020135905060008b8b8481811061182b57fe5b602090810292909201356001600160a01b0316600081815260039093526040909220600181015492935091611861915084612c2e565b600182015588888581811061187257fe5b90506020020135156118c2576040805184815290516001600160a01b038416917f04205018e3978d4e9bf2627d251200b16b790aff8c89cccc4b6e4b226c6c0531919081900360200190a261193a565b6118d2858463ffffffff61224b16565b81549095506118ed906005908886600063ffffffff61241516565b6040805184815267ffffffffffffffff8816602082015281516001600160a01b038516927fb0f2cd2d530eb7a84b780655bd7cd315af71951aedf4ff554889d56cfc3c4ae9928290030190a25b5050506001016117fe565b509998505050505050505050565b6109d5338484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612cc092505050565b606060006119a06120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090611a3957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50611a4261455c565b6040805160e0818101909252611a709186906007908390839080828437600092019190915250612f99915050565b90508060800151604051908082528060200260200182016040528015611aa0578160200160208202803883390190505b50600060e083015292505b806080015182108015611ac25750600a8160e00151105b15611c6157606080611ad38361303b565b909250905060005b825181108015611aee5750836080015185105b15611c4e57600060046000858481518110611b0557fe5b60209081029190910181015182528181019290925260409081016000908120546001600160a01b0316808252600390935290812060c088015160018201549394509092611b579163ffffffff61224b16565b90506000611b6c83896040015160010161221c565b90506000868681518110611b7c57fe5b60200260200101519050828110611c3d576000611b9f828463ffffffff612c2e16565b905083811015611bba57611bba868286038c604001516122e0565b838560010181905550858c8c806001019d5081518110611bd657fe5b60200260200101906001600160a01b031690816001600160a01b031681525050856001600160a01b03167fab9783755c502b2e2e2a8f5d7c88344973a1400de6c46334a7d60d70a17f64588b60c001516040518082815260200191505060405180910390a2505b505060019093019250611adb915050565b50505060e0810180516001019052611aab565b50915091565b60015490565b611c75613084565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f52000081525090611d0e57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5061110e816130d3565b6000611d248383613199565b90505b92915050565b6001600160a01b031660009081526003602052604090205490565b6000611d5460056131da565b905090565b6002546001600160a01b031690565b54151590565b6000611d7d84600085856131f4565b949350505050565b600281015460018201546004909201549092565b60408051808201909152601681527f4a525f494e56414c49445f5a45524f5f414d4f554e5400000000000000000000602082015282611e1c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50611e29838360016120f7565b7fb260c42a00000000000000000000000000000000000000000000000000000000611e538261321f565b7fffffffff00000000000000000000000000000000000000000000000000000000161415611e8657611e86838386612880565b826001600160a01b03167fc65e53b88159e7d2c0fc12a0600072e28ae53ff73b4c1715369c30f16093514283611ebb8661206f565b846040518084815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611f05578181015183820152602001611eed565b50505050905090810190601f168015611f325780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a2600254611f5f906001600160a01b031685308563ffffffff61323b16565b6040518060400160405280601881526020017f4a525f544f4b454e5f5452414e534645525f4641494c45440000000000000000815250906112f357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905260009061206685826132cf565b95945050505050565b60008060008061207e856124f4565b935050925092506120668161209c858561224b90919063ffffffff16565b9063ffffffff61224b16565b60008060009054906101000a90046001600160a01b03166001600160a01b031663db9bee466040518163ffffffff1660e01b815260040160206040518083038186803b1580156111ca57600080fd5b81612101576109d5565b6001600160a01b0383166000908152600360205260409020811561213e576002810154612134908463ffffffff61224b16565b6002820155610a1c565b80600201548311156040518060400160405280601f81526020017f4a525f4e4f545f454e4f5547485f415641494c41424c455f42414c414e434500815250906121cb57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506002018054929092039091555050565b60006121e782611d68565b6121f2576000610d86565b60018201548254610d8691906122109060059063ffffffff61331a16565b9063ffffffff612c2e16565b6005820154600090600484019067ffffffffffffffff848116911614612243576000611d7d565b549392505050565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f57000000000000000000000000000000602082015260009083830190848210156122d857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b509392505050565b6001600160a01b0383166000908152600360209081526040918290206004810180548451808601909552601f85527f4a525f43414e545f5245445543455f444541435449564154494f4e5f524551009385019390935290929091908582101561238d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5084810380835583546123b0906005906001808901908a9063ffffffff61241516565b60018301546040805167ffffffffffffffff92831681526020810184905291871682820152516001600160a01b038916917fc8eaece66ffd12e5066e2ef36d5943fa8fb8104362f92f75152c39788d85b184919081900360600190a250505050505050565b845460408051808201909152601b81527f53554d5f545245455f4b45595f444f45535f4e4f545f45584953540000000000602082015290851061249c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060006124a9868661331a565b90506000826124c7576124c2828563ffffffff612c2e16565b6124d7565b6124d7828563ffffffff61224b16565b90506124e7876000888885613328565b6114f18787878787613354565b6001600160a01b038116600090815260036020526040812081908190819061251b81611d68565b61252657600061253a565b805461253a9060059063ffffffff61331a16565b945061254581611d85565b969891975095945092505050565b60008061255e613476565b67ffffffffffffffff168367ffffffffffffffff1610159050806125925761258d60058463ffffffff6134b816565b61101d565b61101d60058463ffffffff6134d416565b60006125ad610d6c565b6001600160a01b0316633f33bf866040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156125e757600080fd5b505af11580156111de573d6000803e3d6000fd5b6000612605610d6c565b6001600160a01b03166395f3c2da836040518263ffffffff1660e01b8152600401808267ffffffffffffffff1667ffffffffffffffff16815260200191505060206040518083038186803b15801561265c57600080fd5b505afa158015612670573d6000803e3d6000fd5b505050506040513d602081101561268657600080fd5b505192915050565b60006126986125a3565b90506126a483826127a1565b6001600160a01b0383166000908152600360205260409020600481018054600184019291906126d9908663ffffffff61224b16565b815560018101805467ffffffffffffffff191667ffffffffffffffff8516179055815461270c9060059085886000612415565b6040805167ffffffffffffffff851681526020810187905281516001600160a01b038916927fe26ea88625a55cdd86472d3d0e9efd8dd884b5baa05b79bb95a3408df76cede9928290030190a2505050505050565b60008061276c613476565b905061277783611d68565b61278257600061101d565b6001830154835461101d9190612210906005908563ffffffff611d6e16565b6001600160a01b03821660009081526003602052604090206005810154600482019067ffffffffffffffff168015806127ed57508067ffffffffffffffff168467ffffffffffffffff16105b156127fa57505050610e82565b81546001808401805467ffffffffffffffff191690556000845561282190879083906120f7565b6040805167ffffffffffffffff80851682526020820184905287168183015290516001600160a01b038816917f8969a0b11c2c7f08ef80af31a680937503d444cdc933ba9091cdc20f098a7f36919081900360600190a2505050505050565b600061288a6125a3565b905061289684826127a1565b6001600160a01b0384166000908152600360205260408120600201549084156128bf57846128c1565b815b9050600081116040518060400160405280601681526020017f4a525f494e56414c49445f5a45524f5f414d4f554e54000000000000000000008152509061294c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060408051808201909152601c81527f4a525f494e56414c49445f41435449564154494f4e5f414d4f554e54000000006020820152828211156129d357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50600183016129e281836134f0565b6001600160a01b038716600090815260036020526040812090612a04836125fb565b9050612a0f82611d68565b15612ae4578154600090612a2b9060059063ffffffff61331a16565b905081612a3e828763ffffffff61224b16565b10156040518060400160405280601b81526020017f4a525f4143544956455f42414c414e43455f42454c4f575f4d494e000000000081525090612ac557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b508254612ade906005908688600163ffffffff61241516565b50612bc0565b60408051808201909152601b81527f4a525f4143544956455f42414c414e43455f42454c4f575f4d494e0000000000602082015281851015612b6a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50612b7d6005848663ffffffff61359c16565b808355600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038b161790555b612bcc898560006120f7565b6040805167ffffffffffffffff85168152602081018690526001600160a01b03898116828401529151918b16917fee90556a99bb0d072721fedb6d8d458371d132b715762b023fba4d367fbd57b29181900360600190a2505050505050505050565b6000828211156040518060400160405280601281526020017f4d4154485f5355425f554e444552464c4f57000000000000000000000000000081525090612cb957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5050900390565b60408051808201909152601681527f4a525f494e56414c49445f5a45524f5f414d4f554e5400000000000000000000602082015282612d4357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506000612d4e613476565b6001600160a01b0385166000908152600360208190526040909120015490915067ffffffffffffffff16801580612d9857508167ffffffffffffffff168167ffffffffffffffff16105b6040518060400160405280601381526020017f4a525f5749544844524157414c535f4c4f434b0000000000000000000000000081525090612e1d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50612e2885836127a1565b612e34858560006120f7565b846001600160a01b03167faf01bfc8475df280aca00b578c4a948e6d95700f0db8c13365240f7f973c875485612e698861206f565b866040518084815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015612eb3578181015183820152602001612e9b565b50505050905090810190601f168015612ee05780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a2600254612f0c906001600160a01b0316868663ffffffff611fe416565b6040518060400160405280601881526020017f4a525f544f4b454e5f5452414e534645525f4641494c4544000000000000000081525090612f9157604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b505050505050565b612fa161455c565b60408201516000612fb1826125fb565b905060405180610100016040528085600060078110612fcc57fe5b602090810291909101518252868101519082015267ffffffffffffffff84166040820152606080870151908201526080808701519082015260a0808701519082015260c0016130298660066020020151849063ffffffff6135d416565b81526000602090910152949350505050565b60608061307a836000015184602001518560400151866060015187608001518860a001518960e0015160056135fc90979695949392919063ffffffff16565b9094909350915050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166397023f816040518163ffffffff1660e01b815260040160206040518083038186803b1580156111ca57600080fd5b60408051808201909152601d81527f4a525f4241445f544f54414c5f4143544956455f42414c5f4c494d495400000060208201528161315657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50600154604080519182526020820183905280517f9ce60e2304bd08c7c9e6da0e10912e44f85fd9e2ee71c1842132f12146c586c89281900390910190a1600155565b6001600160a01b03821660009081526003602052604081206131ba81611d68565b6131c5576000611d7d565b8054611d7d906005908563ffffffff611d6e16565b6000806131e68361375e565b905061101d8382600061376c565b600083815260028501602090815260408083208584529091528120612066908363ffffffff61379016565b600060048251101561323357506000610d89565b506020015190565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526000906132c586826132cf565b9695505050505050565b6000806040516020818551602087016000895af18015613310573d80156132fd57602081146133065761330e565b6001935061330e565b600183511493505b505b5090949350505050565b6000611d248360008461376c565b6000848152600286016020908152604080832086845290915290206112f390838363ffffffff61379c16565b6000198460006133638861375e565b905060015b8181116133ce5760049390931b929183169160006133878a838661376c565b90506000866133a5576133a0828963ffffffff612c2e16565b6133b5565b6133b5828963ffffffff61224b16565b90506133c48b84878c85613328565b5050600101613368565b508315806133e65750846133e389838561376c565b10155b6040518060400160405280601881526020017f53554d5f545245455f5550444154455f4f564552464c4f5700000000000000008152509061346b57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b505050505050505050565b6000613480610d6c565b6001600160a01b031663f7fe57896040518163ffffffff1660e01b815260040160206040518083038186803b1580156111ca57600080fd5b6000806134c58484613846565b9050611d7d84826000866131f4565b6000806134e18484613846565b9050611d7d848260008661385b565b60006134fb83612553565b9050600061350f828463ffffffff61224b16565b90506001548111156040518060400160405280602081526020017f4a525f544f54414c5f4143544956455f42414c414e43455f4558434545444544815250906112f357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b82546001810184556000906135b2858286613886565b8215611d7d576135c6856000838787613328565b611d7d858286866001613354565b60006127106135ed8461ffff851663ffffffff6138d716565b816135f457fe5b049392505050565b60608060008061360f8c8a8a8a8a61397a565b9150915060606136238c8c888b87876139e8565b90506136368d828c63ffffffff613be016565b8051825160408051808201909152601f81527f545245455f534f52544954494f4e5f4c454e475448535f4d49534d41544348006020820152939850919650146136c357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50878551146040518060400160405280601f81526020017f545245455f534f52544954494f4e5f4c454e475448535f4d49534d41544348008152509061374d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b505050509850989650505050505050565b6000610d8682600101613dfe565b600082815260028401602090815260408083208484529091528120611d7d90613dfe565b6000611d248383613e5f565b60408051808201909152601881527f434845434b504f494e545f56414c55455f544f4f5f4249470000000000000000602082015277ffffffffffffffffffffffffffffffffffffffffffffffff82111561383a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506109d5838383614033565b6000611d24600184018363ffffffff6141ef16565b600083815260028501602090815260408083208584529091528120612066908363ffffffff6141ef16565b60006138918461375e565b905061389d81846141fb565b15610a1c576001810160006138b386848361376c565b90506138c3868360008785613328565b612f9160018701858463ffffffff61379c16565b6000826138e657506000611d27565b828202828482816138f357fe5b04146040518060400160405280601181526020017f4d4154485f4d554c5f4f564552464c4f57000000000000000000000000000000815250906122d857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b6000808061398e888863ffffffff6134d416565b90506139b0846139a4888463ffffffff6138d716565b9063ffffffff61422116565b925060006139c4878763ffffffff61224b16565b90506139da856139a4838563ffffffff6138d716565b925050509550959350505050565b60608282116040518060400160405280601c81526020017f545245455f494e56414c49445f494e54455256414c5f5345415243480000000081525090613a7257604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060008383039050606085604051908082528060200260200182016040528015613aa6578160200160208202803883390190505b50905060005b86811015613bd3576040805160208082018d90528183018c9052606082018b905260808083018590528351808403909101815260a09092019092528051910120613b07848281613af857fe5b8991900663ffffffff61224b16565b838381518110613b1357fe5b6020908102919091010152815b600081118015613b585750836001820381518110613b3a57fe5b6020026020010151848281518110613b4e57fe5b6020026020010151105b15613bc9576000846001830381518110613b6e57fe5b60200260200101519050848281518110613b8457fe5b6020026020010151856001840381518110613b9b57fe5b60200260200101818152505080858381518110613bb457fe5b60209081029190910101525060001901613b20565b5050600101613aac565b5098975050505050505050565b60608060008451116040518060400160405280601e81526020017f53554d5f545245455f4d495353494e475f5345415243485f56414c554553000081525090613c6d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506000613c7a86856134d4565b9050600081118015613ca2575084600186510381518110613c9757fe5b602002602001015181115b6040518060400160405280601d81526020017f53554d5f545245455f5345415243485f4f55545f4f465f424f554e445300000081525090613d2757604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506000613d348786613846565b9050613d3e6145ae565b6040805160a0810190915267ffffffffffffffff8716815260208101613d6b84600163ffffffff612c2e16565b815260200160008152602001600081526020016000815250905060008751905080604051908082528060200260200182016040528015613db5578160200160208202803883390190505b50955080604051908082528060200260200182016040528015613de2578160200160208202803883390190505b509450613df289898489896142c0565b50505050935093915050565b80546000908015613e5657826000016001820381548110613e1b57fe5b60009182526020909120015468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff169150610d899050565b50600092915050565b815460009080613e73576000915050611d27565b8354600019820190859082908110613e8757fe5b60009182526020909120015467ffffffffffffffff90811690851610613ef257846000018181548110613eb657fe5b60009182526020909120015468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff169250611d27915050565b84600001600081548110613f0257fe5b60009182526020909120015467ffffffffffffffff9081169085161015613f2e57600092505050611d27565b6000815b81811115613fe757865460028383016001010490600090899083908110613f5557fe5b6000918252602090912001805490915067ffffffffffffffff908116908916811015613f8357829450613fdf565b8067ffffffffffffffff168967ffffffffffffffff161015613faa57600183039350613fdf565b505468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff169550611d27945050505050565b505050613f32565b866000018281548110613ff657fe5b60009182526020909120015468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff16979650505050505050565b82548015806140735750835467ffffffffffffffff8416908590600019810190811061405b57fe5b60009182526020909120015467ffffffffffffffff16105b156140fa576040805180820190915267ffffffffffffffff808516825277ffffffffffffffffffffffffffffffffffffffffffffffff80851660208085019182528854600181018a5560008a8152919091209451940180549151909216680100000000000000000293831667ffffffffffffffff1990911617909116919091179055610a1c565b600084600001600183038154811061410e57fe5b6000918252602091829020018054604080518082019091528381527f434845434b504f494e545f43414e4e4f545f4144445f504153545f56414c55459381019390935290925067ffffffffffffffff8681169116146141b157604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50805477ffffffffffffffffffffffffffffffffffffffffffffffff8416680100000000000000000267ffffffffffffffff90911617905550505050565b6000611d248383614408565b60008061420f84600463ffffffff6138d716565b600019901b8316151591505092915050565b60008082116040518060400160405280600d81526020017f4d4154485f4449565f5a45524f00000000000000000000000000000000000000815250906142ab57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060008284816142b757fe5b04949350505050565b60208301516000906142d990600463ffffffff6138d716565b905060005b60108110156114f15785518560600151106142f8576114f1565b60408501516000906143129083851b63ffffffff61224b16565b9050600061432a898860200151848a6000015161385b565b9050600061434582896080015161224b90919063ffffffff16565b905060006143588a8a60600151846144d6565b905080156143f85760208901516143805761437b896060015182868b878c614514565b6143dd565b6143886145ae565b6040518060a001604052808b6000015167ffffffffffffffff16815260200160018c602001510381526020018681526020018b6060015181526020018b6080015181525090506143db8c8c838c8c6142c0565b505b60608901516143f2908263ffffffff61224b16565b60608a01525b50608088015250506001016142de565b81546000908061441c576000915050611d27565b835460001982019060009086908390811061443357fe5b9060005260206000200190505b60008211801561445d5750805467ffffffffffffffff8087169116115b156144885785546000199092019186908390811061447757fe5b906000526020600020019050614440565b805467ffffffffffffffff8087169116116144ca57805468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff166132c5565b60009695505050505050565b6000825b8451811080156144fc5750828582815181106144f257fe5b6020026020010151105b15614509576001016144da565b929092039392505050565b60005b858110156114f15784848289018151811061452e57fe5b60200260200101818152505082828289018151811061454957fe5b6020908102919091010152600101614517565b6040518061010001604052806000801916815260200160008152602001600067ffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060a00160405280600067ffffffffffffffff168152602001600081526020016000815260200160008152602001600081525090565b6145fe60018281019060009063ffffffff61379c16565b6000905556fea165627a7a723058200f1569b86ba4df4896c73943c86f522b57715b54798a50aae9ef13dfef05753f0029000000000000000000000000ee4650cbe7a2b23701d416f58b41d8b76b617797000000000000000000000000cd62b1c403fa761baadfc74c525ce2b51780b184000000000000000000000000000000008ac7230489e7feb210d3bd1429c00000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101da5760003560e01c8063916b9bef11610104578063c8fd6ed0116100a2578063e9e67d6711610071578063e9e67d67146108c7578063f01e7d03146108fd578063f590e92314610923578063fc0c546a1461092b576101da565b8063c8fd6ed0146107b4578063d903bcf41461082b578063dbbd85a6146108a2578063e67a81f4146108aa576101da565b8063af7a9f40116100de578063af7a9f40146105f9578063af8b9d0f1461063c578063b260c42a14610672578063c67106f51461068f576101da565b8063916b9bef1461059057806396a705c1146105ad578063ac8fcfc0146105d3576101da565b8063605da1b21161017c57806370a082311161014b57806370a08231146104ac578063817b1cd2146104d25780638e127793146104da5780638f4ffcb114610501576101da565b8063605da1b2146103ef5780636d1b229d1461043f5780636d6cc6841461045c5780637033e4a6146104a4576101da565b806324ae6a27116101b857806324ae6a27146103395780633018205f146103675780634b341aed1461038b5780634d7edc15146103c3576101da565b8063082b4235146101df5780630e89439b1461023b5780630ef96356146102b4575b600080fd5b610215600480360360408110156101f557600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff16610933565b604080519485526020850193909352838301919091526060830152519081900360800190f35b6102b26004803603604081101561025157600080fd5b8135919081019060408101602082013564010000000081111561027357600080fd5b82018360208201111561028557600080fd5b803590602001918460018302840111640100000000831117156102a757600080fd5b509092509050610993565b005b6102b2600480360360608110156102ca57600080fd5b6001600160a01b03823516916020810135918101906060810160408201356401000000008111156102fa57600080fd5b82018360208201111561030c57600080fd5b8035906020019184600183028401116401000000008311171561032e57600080fd5b5090925090506109da565b6102b26004803603604081101561034f57600080fd5b506001600160a01b0381358116916020013516610a22565b61036f610d6c565b604080516001600160a01b039092168252519081900360200190f35b6103b1600480360360208110156103a157600080fd5b50356001600160a01b0316610d7b565b60408051918252519081900360200190f35b6102b2600480360360408110156103d957600080fd5b506001600160a01b038135169060200135610d8e565b61042b6004803603606081101561040557600080fd5b5080356001600160a01b0316906020810135906040013567ffffffffffffffff16610e86565b604080519115158252519081900360200190f35b6102b26004803603602081101561045557600080fd5b5035611024565b6104826004803603602081101561047257600080fd5b50356001600160a01b0316611111565b6040805192835267ffffffffffffffff90911660208301528051918290030190f35b61042b611143565b610215600480360360208110156104c257600080fd5b50356001600160a01b0316611148565b6103b1611166565b6103b1600480360360208110156104f057600080fd5b503567ffffffffffffffff166111fb565b6102b26004803603608081101561051757600080fd5b6001600160a01b03823581169260208101359260408201359092169181019060808101606082013564010000000081111561055157600080fd5b82018360208201111561056357600080fd5b8035906020019184600183028401116401000000008311171561058557600080fd5b509092509050611206565b6102b2600480360360208110156105a657600080fd5b50356112fa565b6103b1600480360360208110156105c357600080fd5b50356001600160a01b03166114fa565b6102b2600480360360208110156105e957600080fd5b50356001600160a01b031661151b565b61061f6004803603602081101561060f57600080fd5b50356001600160a01b0316611531565b6040805167ffffffffffffffff9092168252519081900360200190f35b6102b26004803603604081101561065257600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff1661155a565b6102b26004803603602081101561068857600080fd5b503561163b565b6103b1600480360360808110156106a557600080fd5b67ffffffffffffffff82351691908101906040810160208201356401000000008111156106d157600080fd5b8201836020820111156106e357600080fd5b8035906020019184602083028401116401000000008311171561070557600080fd5b91939092909160208101903564010000000081111561072357600080fd5b82018360208201111561073557600080fd5b8035906020019184602083028401116401000000008311171561075757600080fd5b91939092909160208101903564010000000081111561077557600080fd5b82018360208201111561078757600080fd5b803590602001918460208302840111640100000000831117156107a957600080fd5b509092509050611646565b6102b2600480360360408110156107ca57600080fd5b813591908101906040810160208201356401000000008111156107ec57600080fd5b8201836020820111156107fe57600080fd5b8035906020019184600183028401116401000000008311171561082057600080fd5b509092509050611953565b610847600480360360e081101561084157600080fd5b50611994565b6040518080602001838152602001828103825284818151815260200191508051906020019060200280838360005b8381101561088d578181015183820152602001610875565b50505050905001935050505060405180910390f35b6103b1611c67565b6102b2600480360360208110156108c057600080fd5b5035611c6d565b6103b1600480360360408110156108dd57600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff16611d18565b6103b16004803603602081101561091357600080fd5b50356001600160a01b0316611d2d565b6103b1611d48565b61036f611d59565b6001600160a01b038216600090815260036020526040812081908190819061095a81611d68565b61096557600061097a565b805461097a906005908863ffffffff611d6e16565b945061098581611d85565b969991985096509350505050565b6109d533338585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d9992505050565b505050565b610a1c33858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d9992505050565b50505050565b6000809054906101000a90046001600160a01b03166001600160a01b0316633c28e88b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a6f57600080fd5b505afa158015610a83573d6000803e3d6000fd5b505050506040513d6020811015610a9957600080fd5b505160408051808201909152601d81527f4354445f53454e4445525f4e4f545f46554e44535f474f5645524e4f520000006020820152906001600160a01b03163314610b6657604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610b2b578181015183820152602001610b13565b50505050905090810190601f168015610b585780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290516000916001600160a01b038516916370a0823191602480820192602092909190829003018186803b158015610bca57600080fd5b505afa158015610bde573d6000803e3d6000fd5b505050506040513d6020811015610bf457600080fd5b505160408051808201909152601e81527f4354445f494e53554646494349454e545f5245434f5645525f46554e44530000602082015290915081610c7c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50610c976001600160a01b038416838363ffffffff611fe416565b6040518060400160405280601e81526020017f4354445f5245434f5645525f544f4b454e5f46554e44535f4641494c4544000081525090610d1c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50604080516001600160a01b0380861682528416602082015280820183905290517f724139fea3954691c2c1ee02b3be6be1763b32ec84841f1acad6d3a18695ba0d9181900360600190a1505050565b6000546001600160a01b031690565b6000610d868261206f565b90505b919050565b610d966120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090610e2f57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b508015610e8257610e42828260016120f7565b6040805182815290516001600160a01b038416917fbfbd6786419e534c0af90164d33c027ddc81c4541f1047d00bb286d5d4dfe8a7919081900360200190a25b5050565b6000610e906120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090610f2957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5082610f375750600161101d565b6001600160a01b03841660009081526003602052604081206001840191610f5d826121dc565b90506000610f6b838561221c565b90506000610f7f838363ffffffff61224b16565b905080881115610f975760009550505050505061101d565b82881115610faf57828803610fad8a828a6122e0565b505b8354610fc790600590878b600063ffffffff61241516565b6040805189815267ffffffffffffffff8716602082015281516001600160a01b038c16927f3b522789764bf3f50da1a4e79a6b330fd1ae121df88d89259fa73b55e1e9e360928290030190a26001955050505050505b9392505050565b61102c6120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c450000815250906110c557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50801561110e576110da61dead8260016120f7565b6040805182815290517fef08526ce447c7a59448d28b89b25b9be13b2ae0293946c9cf27123c8e71a3769181900360200190a15b50565b6001600160a01b0381166000908152600360205260409020600481015460059091015467ffffffffffffffff16915091565b600090565b600080600080611157856124f4565b93509350935093509193509193565b600254604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156111ca57600080fd5b505afa1580156111de573d6000803e3d6000fd5b505050506040513d60208110156111f457600080fd5b5051905090565b6000610d8682612553565b336001600160a01b03841614801561122b57506002546001600160a01b038481169116145b6040518060400160405280601c81526020017f4a525f544f4b454e5f415050524f56455f4e4f545f414c4c4f57454400000000815250906112b057604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506112f385868685858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d9992505050565b5050505050565b60006113046125a3565b33600090815260036020526040812091925061131f826121dc565b90506000841561132f5784611331565b815b9050600081116040518060400160405280601681526020017f4a525f494e56414c49445f5a45524f5f414d4f554e5400000000000000000000815250906113bc57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060408051808201909152601e81527f4a525f494e56414c49445f444541435449564154494f4e5f414d4f554e54000060208201528282111561144357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b508082036000611452866125fb565b90508115806114615750808210155b6040518060400160405280601e81526020017f4a525f494e56414c49445f444541435449564154494f4e5f414d4f554e540000815250906114e657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506114f1338461268e565b50505050505050565b6001600160a01b038116600090815260036020526040812061101d81612761565b60006115256125a3565b9050610e8282826127a1565b6001600160a01b03166000908152600360208190526040909120015467ffffffffffffffff1690565b6115626120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c450000815250906115fb57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506001600160a01b0391909116600090815260036020819052604090912001805467ffffffffffffffff191667ffffffffffffffff909216919091179055565b61110e338233612880565b60006116506120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c450000815250906116e957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060408051808201909152601d81527f4a525f494e56414c49445f4c4f434b45445f414d4f554e54535f4c454e000000602082015286851461176f57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060408051808201909152601e81527f4a525f494e56414c49445f52455741524445445f4a55524f52535f4c454e000060208201528683146117f557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50600188016000805b8881101561194557600088888381811061181457fe5b90506020020135905060008b8b8481811061182b57fe5b602090810292909201356001600160a01b0316600081815260039093526040909220600181015492935091611861915084612c2e565b600182015588888581811061187257fe5b90506020020135156118c2576040805184815290516001600160a01b038416917f04205018e3978d4e9bf2627d251200b16b790aff8c89cccc4b6e4b226c6c0531919081900360200190a261193a565b6118d2858463ffffffff61224b16565b81549095506118ed906005908886600063ffffffff61241516565b6040805184815267ffffffffffffffff8816602082015281516001600160a01b038516927fb0f2cd2d530eb7a84b780655bd7cd315af71951aedf4ff554889d56cfc3c4ae9928290030190a25b5050506001016117fe565b509998505050505050505050565b6109d5338484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612cc092505050565b606060006119a06120a8565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f44495350555445535f4d4f44554c45000081525090611a3957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50611a4261455c565b6040805160e0818101909252611a709186906007908390839080828437600092019190915250612f99915050565b90508060800151604051908082528060200260200182016040528015611aa0578160200160208202803883390190505b50600060e083015292505b806080015182108015611ac25750600a8160e00151105b15611c6157606080611ad38361303b565b909250905060005b825181108015611aee5750836080015185105b15611c4e57600060046000858481518110611b0557fe5b60209081029190910181015182528181019290925260409081016000908120546001600160a01b0316808252600390935290812060c088015160018201549394509092611b579163ffffffff61224b16565b90506000611b6c83896040015160010161221c565b90506000868681518110611b7c57fe5b60200260200101519050828110611c3d576000611b9f828463ffffffff612c2e16565b905083811015611bba57611bba868286038c604001516122e0565b838560010181905550858c8c806001019d5081518110611bd657fe5b60200260200101906001600160a01b031690816001600160a01b031681525050856001600160a01b03167fab9783755c502b2e2e2a8f5d7c88344973a1400de6c46334a7d60d70a17f64588b60c001516040518082815260200191505060405180910390a2505b505060019093019250611adb915050565b50505060e0810180516001019052611aab565b50915091565b60015490565b611c75613084565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f52000081525090611d0e57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5061110e816130d3565b6000611d248383613199565b90505b92915050565b6001600160a01b031660009081526003602052604090205490565b6000611d5460056131da565b905090565b6002546001600160a01b031690565b54151590565b6000611d7d84600085856131f4565b949350505050565b600281015460018201546004909201549092565b60408051808201909152601681527f4a525f494e56414c49445f5a45524f5f414d4f554e5400000000000000000000602082015282611e1c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50611e29838360016120f7565b7fb260c42a00000000000000000000000000000000000000000000000000000000611e538261321f565b7fffffffff00000000000000000000000000000000000000000000000000000000161415611e8657611e86838386612880565b826001600160a01b03167fc65e53b88159e7d2c0fc12a0600072e28ae53ff73b4c1715369c30f16093514283611ebb8661206f565b846040518084815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611f05578181015183820152602001611eed565b50505050905090810190601f168015611f325780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a2600254611f5f906001600160a01b031685308563ffffffff61323b16565b6040518060400160405280601881526020017f4a525f544f4b454e5f5452414e534645525f4641494c45440000000000000000815250906112f357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905260009061206685826132cf565b95945050505050565b60008060008061207e856124f4565b935050925092506120668161209c858561224b90919063ffffffff16565b9063ffffffff61224b16565b60008060009054906101000a90046001600160a01b03166001600160a01b031663db9bee466040518163ffffffff1660e01b815260040160206040518083038186803b1580156111ca57600080fd5b81612101576109d5565b6001600160a01b0383166000908152600360205260409020811561213e576002810154612134908463ffffffff61224b16565b6002820155610a1c565b80600201548311156040518060400160405280601f81526020017f4a525f4e4f545f454e4f5547485f415641494c41424c455f42414c414e434500815250906121cb57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506002018054929092039091555050565b60006121e782611d68565b6121f2576000610d86565b60018201548254610d8691906122109060059063ffffffff61331a16565b9063ffffffff612c2e16565b6005820154600090600484019067ffffffffffffffff848116911614612243576000611d7d565b549392505050565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f57000000000000000000000000000000602082015260009083830190848210156122d857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b509392505050565b6001600160a01b0383166000908152600360209081526040918290206004810180548451808601909552601f85527f4a525f43414e545f5245445543455f444541435449564154494f4e5f524551009385019390935290929091908582101561238d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5084810380835583546123b0906005906001808901908a9063ffffffff61241516565b60018301546040805167ffffffffffffffff92831681526020810184905291871682820152516001600160a01b038916917fc8eaece66ffd12e5066e2ef36d5943fa8fb8104362f92f75152c39788d85b184919081900360600190a250505050505050565b845460408051808201909152601b81527f53554d5f545245455f4b45595f444f45535f4e4f545f45584953540000000000602082015290851061249c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060006124a9868661331a565b90506000826124c7576124c2828563ffffffff612c2e16565b6124d7565b6124d7828563ffffffff61224b16565b90506124e7876000888885613328565b6114f18787878787613354565b6001600160a01b038116600090815260036020526040812081908190819061251b81611d68565b61252657600061253a565b805461253a9060059063ffffffff61331a16565b945061254581611d85565b969891975095945092505050565b60008061255e613476565b67ffffffffffffffff168367ffffffffffffffff1610159050806125925761258d60058463ffffffff6134b816565b61101d565b61101d60058463ffffffff6134d416565b60006125ad610d6c565b6001600160a01b0316633f33bf866040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156125e757600080fd5b505af11580156111de573d6000803e3d6000fd5b6000612605610d6c565b6001600160a01b03166395f3c2da836040518263ffffffff1660e01b8152600401808267ffffffffffffffff1667ffffffffffffffff16815260200191505060206040518083038186803b15801561265c57600080fd5b505afa158015612670573d6000803e3d6000fd5b505050506040513d602081101561268657600080fd5b505192915050565b60006126986125a3565b90506126a483826127a1565b6001600160a01b0383166000908152600360205260409020600481018054600184019291906126d9908663ffffffff61224b16565b815560018101805467ffffffffffffffff191667ffffffffffffffff8516179055815461270c9060059085886000612415565b6040805167ffffffffffffffff851681526020810187905281516001600160a01b038916927fe26ea88625a55cdd86472d3d0e9efd8dd884b5baa05b79bb95a3408df76cede9928290030190a2505050505050565b60008061276c613476565b905061277783611d68565b61278257600061101d565b6001830154835461101d9190612210906005908563ffffffff611d6e16565b6001600160a01b03821660009081526003602052604090206005810154600482019067ffffffffffffffff168015806127ed57508067ffffffffffffffff168467ffffffffffffffff16105b156127fa57505050610e82565b81546001808401805467ffffffffffffffff191690556000845561282190879083906120f7565b6040805167ffffffffffffffff80851682526020820184905287168183015290516001600160a01b038816917f8969a0b11c2c7f08ef80af31a680937503d444cdc933ba9091cdc20f098a7f36919081900360600190a2505050505050565b600061288a6125a3565b905061289684826127a1565b6001600160a01b0384166000908152600360205260408120600201549084156128bf57846128c1565b815b9050600081116040518060400160405280601681526020017f4a525f494e56414c49445f5a45524f5f414d4f554e54000000000000000000008152509061294c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060408051808201909152601c81527f4a525f494e56414c49445f41435449564154494f4e5f414d4f554e54000000006020820152828211156129d357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50600183016129e281836134f0565b6001600160a01b038716600090815260036020526040812090612a04836125fb565b9050612a0f82611d68565b15612ae4578154600090612a2b9060059063ffffffff61331a16565b905081612a3e828763ffffffff61224b16565b10156040518060400160405280601b81526020017f4a525f4143544956455f42414c414e43455f42454c4f575f4d494e000000000081525090612ac557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b508254612ade906005908688600163ffffffff61241516565b50612bc0565b60408051808201909152601b81527f4a525f4143544956455f42414c414e43455f42454c4f575f4d494e0000000000602082015281851015612b6a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50612b7d6005848663ffffffff61359c16565b808355600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038b161790555b612bcc898560006120f7565b6040805167ffffffffffffffff85168152602081018690526001600160a01b03898116828401529151918b16917fee90556a99bb0d072721fedb6d8d458371d132b715762b023fba4d367fbd57b29181900360600190a2505050505050505050565b6000828211156040518060400160405280601281526020017f4d4154485f5355425f554e444552464c4f57000000000000000000000000000081525090612cb957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5050900390565b60408051808201909152601681527f4a525f494e56414c49445f5a45524f5f414d4f554e5400000000000000000000602082015282612d4357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506000612d4e613476565b6001600160a01b0385166000908152600360208190526040909120015490915067ffffffffffffffff16801580612d9857508167ffffffffffffffff168167ffffffffffffffff16105b6040518060400160405280601381526020017f4a525f5749544844524157414c535f4c4f434b0000000000000000000000000081525090612e1d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50612e2885836127a1565b612e34858560006120f7565b846001600160a01b03167faf01bfc8475df280aca00b578c4a948e6d95700f0db8c13365240f7f973c875485612e698861206f565b866040518084815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015612eb3578181015183820152602001612e9b565b50505050905090810190601f168015612ee05780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a2600254612f0c906001600160a01b0316868663ffffffff611fe416565b6040518060400160405280601881526020017f4a525f544f4b454e5f5452414e534645525f4641494c4544000000000000000081525090612f9157604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b505050505050565b612fa161455c565b60408201516000612fb1826125fb565b905060405180610100016040528085600060078110612fcc57fe5b602090810291909101518252868101519082015267ffffffffffffffff84166040820152606080870151908201526080808701519082015260a0808701519082015260c0016130298660066020020151849063ffffffff6135d416565b81526000602090910152949350505050565b60608061307a836000015184602001518560400151866060015187608001518860a001518960e0015160056135fc90979695949392919063ffffffff16565b9094909350915050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166397023f816040518163ffffffff1660e01b815260040160206040518083038186803b1580156111ca57600080fd5b60408051808201909152601d81527f4a525f4241445f544f54414c5f4143544956455f42414c5f4c494d495400000060208201528161315657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50600154604080519182526020820183905280517f9ce60e2304bd08c7c9e6da0e10912e44f85fd9e2ee71c1842132f12146c586c89281900390910190a1600155565b6001600160a01b03821660009081526003602052604081206131ba81611d68565b6131c5576000611d7d565b8054611d7d906005908563ffffffff611d6e16565b6000806131e68361375e565b905061101d8382600061376c565b600083815260028501602090815260408083208584529091528120612066908363ffffffff61379016565b600060048251101561323357506000610d89565b506020015190565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526000906132c586826132cf565b9695505050505050565b6000806040516020818551602087016000895af18015613310573d80156132fd57602081146133065761330e565b6001935061330e565b600183511493505b505b5090949350505050565b6000611d248360008461376c565b6000848152600286016020908152604080832086845290915290206112f390838363ffffffff61379c16565b6000198460006133638861375e565b905060015b8181116133ce5760049390931b929183169160006133878a838661376c565b90506000866133a5576133a0828963ffffffff612c2e16565b6133b5565b6133b5828963ffffffff61224b16565b90506133c48b84878c85613328565b5050600101613368565b508315806133e65750846133e389838561376c565b10155b6040518060400160405280601881526020017f53554d5f545245455f5550444154455f4f564552464c4f5700000000000000008152509061346b57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b505050505050505050565b6000613480610d6c565b6001600160a01b031663f7fe57896040518163ffffffff1660e01b815260040160206040518083038186803b1580156111ca57600080fd5b6000806134c58484613846565b9050611d7d84826000866131f4565b6000806134e18484613846565b9050611d7d848260008661385b565b60006134fb83612553565b9050600061350f828463ffffffff61224b16565b90506001548111156040518060400160405280602081526020017f4a525f544f54414c5f4143544956455f42414c414e43455f4558434545444544815250906112f357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b82546001810184556000906135b2858286613886565b8215611d7d576135c6856000838787613328565b611d7d858286866001613354565b60006127106135ed8461ffff851663ffffffff6138d716565b816135f457fe5b049392505050565b60608060008061360f8c8a8a8a8a61397a565b9150915060606136238c8c888b87876139e8565b90506136368d828c63ffffffff613be016565b8051825160408051808201909152601f81527f545245455f534f52544954494f4e5f4c454e475448535f4d49534d41544348006020820152939850919650146136c357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50878551146040518060400160405280601f81526020017f545245455f534f52544954494f4e5f4c454e475448535f4d49534d41544348008152509061374d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b505050509850989650505050505050565b6000610d8682600101613dfe565b600082815260028401602090815260408083208484529091528120611d7d90613dfe565b6000611d248383613e5f565b60408051808201909152601881527f434845434b504f494e545f56414c55455f544f4f5f4249470000000000000000602082015277ffffffffffffffffffffffffffffffffffffffffffffffff82111561383a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506109d5838383614033565b6000611d24600184018363ffffffff6141ef16565b600083815260028501602090815260408083208584529091528120612066908363ffffffff6141ef16565b60006138918461375e565b905061389d81846141fb565b15610a1c576001810160006138b386848361376c565b90506138c3868360008785613328565b612f9160018701858463ffffffff61379c16565b6000826138e657506000611d27565b828202828482816138f357fe5b04146040518060400160405280601181526020017f4d4154485f4d554c5f4f564552464c4f57000000000000000000000000000000815250906122d857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b6000808061398e888863ffffffff6134d416565b90506139b0846139a4888463ffffffff6138d716565b9063ffffffff61422116565b925060006139c4878763ffffffff61224b16565b90506139da856139a4838563ffffffff6138d716565b925050509550959350505050565b60608282116040518060400160405280601c81526020017f545245455f494e56414c49445f494e54455256414c5f5345415243480000000081525090613a7257604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060008383039050606085604051908082528060200260200182016040528015613aa6578160200160208202803883390190505b50905060005b86811015613bd3576040805160208082018d90528183018c9052606082018b905260808083018590528351808403909101815260a09092019092528051910120613b07848281613af857fe5b8991900663ffffffff61224b16565b838381518110613b1357fe5b6020908102919091010152815b600081118015613b585750836001820381518110613b3a57fe5b6020026020010151848281518110613b4e57fe5b6020026020010151105b15613bc9576000846001830381518110613b6e57fe5b60200260200101519050848281518110613b8457fe5b6020026020010151856001840381518110613b9b57fe5b60200260200101818152505080858381518110613bb457fe5b60209081029190910101525060001901613b20565b5050600101613aac565b5098975050505050505050565b60608060008451116040518060400160405280601e81526020017f53554d5f545245455f4d495353494e475f5345415243485f56414c554553000081525090613c6d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506000613c7a86856134d4565b9050600081118015613ca2575084600186510381518110613c9757fe5b602002602001015181115b6040518060400160405280601d81526020017f53554d5f545245455f5345415243485f4f55545f4f465f424f554e445300000081525090613d2757604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b506000613d348786613846565b9050613d3e6145ae565b6040805160a0810190915267ffffffffffffffff8716815260208101613d6b84600163ffffffff612c2e16565b815260200160008152602001600081526020016000815250905060008751905080604051908082528060200260200182016040528015613db5578160200160208202803883390190505b50955080604051908082528060200260200182016040528015613de2578160200160208202803883390190505b509450613df289898489896142c0565b50505050935093915050565b80546000908015613e5657826000016001820381548110613e1b57fe5b60009182526020909120015468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff169150610d899050565b50600092915050565b815460009080613e73576000915050611d27565b8354600019820190859082908110613e8757fe5b60009182526020909120015467ffffffffffffffff90811690851610613ef257846000018181548110613eb657fe5b60009182526020909120015468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff169250611d27915050565b84600001600081548110613f0257fe5b60009182526020909120015467ffffffffffffffff9081169085161015613f2e57600092505050611d27565b6000815b81811115613fe757865460028383016001010490600090899083908110613f5557fe5b6000918252602090912001805490915067ffffffffffffffff908116908916811015613f8357829450613fdf565b8067ffffffffffffffff168967ffffffffffffffff161015613faa57600183039350613fdf565b505468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff169550611d27945050505050565b505050613f32565b866000018281548110613ff657fe5b60009182526020909120015468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff16979650505050505050565b82548015806140735750835467ffffffffffffffff8416908590600019810190811061405b57fe5b60009182526020909120015467ffffffffffffffff16105b156140fa576040805180820190915267ffffffffffffffff808516825277ffffffffffffffffffffffffffffffffffffffffffffffff80851660208085019182528854600181018a5560008a8152919091209451940180549151909216680100000000000000000293831667ffffffffffffffff1990911617909116919091179055610a1c565b600084600001600183038154811061410e57fe5b6000918252602091829020018054604080518082019091528381527f434845434b504f494e545f43414e4e4f545f4144445f504153545f56414c55459381019390935290925067ffffffffffffffff8681169116146141b157604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b50805477ffffffffffffffffffffffffffffffffffffffffffffffff8416680100000000000000000267ffffffffffffffff90911617905550505050565b6000611d248383614408565b60008061420f84600463ffffffff6138d716565b600019901b8316151591505092915050565b60008082116040518060400160405280600d81526020017f4d4154485f4449565f5a45524f00000000000000000000000000000000000000815250906142ab57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610b2b578181015183820152602001610b13565b5060008284816142b757fe5b04949350505050565b60208301516000906142d990600463ffffffff6138d716565b905060005b60108110156114f15785518560600151106142f8576114f1565b60408501516000906143129083851b63ffffffff61224b16565b9050600061432a898860200151848a6000015161385b565b9050600061434582896080015161224b90919063ffffffff16565b905060006143588a8a60600151846144d6565b905080156143f85760208901516143805761437b896060015182868b878c614514565b6143dd565b6143886145ae565b6040518060a001604052808b6000015167ffffffffffffffff16815260200160018c602001510381526020018681526020018b6060015181526020018b6080015181525090506143db8c8c838c8c6142c0565b505b60608901516143f2908263ffffffff61224b16565b60608a01525b50608088015250506001016142de565b81546000908061441c576000915050611d27565b835460001982019060009086908390811061443357fe5b9060005260206000200190505b60008211801561445d5750805467ffffffffffffffff8087169116115b156144885785546000199092019186908390811061447757fe5b906000526020600020019050614440565b805467ffffffffffffffff8087169116116144ca57805468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff166132c5565b60009695505050505050565b6000825b8451811080156144fc5750828582815181106144f257fe5b6020026020010151105b15614509576001016144da565b929092039392505050565b60005b858110156114f15784848289018151811061452e57fe5b60200260200101818152505082828289018151811061454957fe5b6020908102919091010152600101614517565b6040518061010001604052806000801916815260200160008152602001600067ffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060a00160405280600067ffffffffffffffff168152602001600081526020016000815260200160008152602001600081525090565b6145fe60018281019060009063ffffffff61379c16565b6000905556fea165627a7a723058200f1569b86ba4df4896c73943c86f522b57715b54798a50aae9ef13dfef05753f0029
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ee4650cbe7a2b23701d416f58b41d8b76b617797000000000000000000000000cd62b1c403fa761baadfc74c525ce2b51780b184000000000000000000000000000000008ac7230489e7feb210d3bd1429c00000
-----Decoded View---------------
Arg [0] : _controller (address): 0xee4650cBe7a2B23701D416f58b41D8B76b617797
Arg [1] : _jurorToken (address): 0xcD62b1C403fa761BAadFC74C525ce2B51780b184
Arg [2] : _totalActiveBalanceLimit (uint256): 184467440737095510000000000000000000000
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000ee4650cbe7a2b23701d416f58b41d8b76b617797
Arg [1] : 000000000000000000000000cd62b1c403fa761baadfc74c525ce2b51780b184
Arg [2] : 000000000000000000000000000000008ac7230489e7feb210d3bd1429c00000
Deployed Bytecode Sourcemap
157628:46042:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;157628:46042:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;182110:388;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;182110:388:0;;-1:-1:-1;;;;;182110:388:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;166943:128;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;166943:128:0;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;166943:128:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;166943:128:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;166943:128:0;;-1:-1:-1;166943:128:0;-1:-1:-1;166943:128:0;:::i;:::-;;167391:137;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;167391:137:0;;;;;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;167391:137:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;167391:137:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;167391:137:0;;-1:-1:-1;167391:137:0;-1:-1:-1;167391:137:0;:::i;157172:346::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;157172:346:0;;;;;;;;;;:::i;152258:96::-;;;:::i;:::-;;;;-1:-1:-1;;;;;152258:96:0;;;;;;;;;;;;;;180796:121;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;180796:121:0;-1:-1:-1;;;;;180796:121:0;;:::i;:::-;;;;;;;;;;;;;;;;169157:249;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;169157:249:0;;;;;;;;:::i;176522:1661::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;176522:1661:0;;-1:-1:-1;;;;;176522:1661:0;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;169541:227;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;169541:227:0;;:::i;183762:270::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;183762:270:0;-1:-1:-1;;;;;183762:270:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;185278:87;;;:::i;181374:182::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;181374:182:0;-1:-1:-1;;;;;181374:182:0;;:::i;179512:117::-;;;:::i;180108:134::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;180108:134:0;;;;:::i;168266:266::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;168266:266:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;168266:266:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;168266:266:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;168266:266:0;;-1:-1:-1;168266:266:0;-1:-1:-1;168266:266:0;:::i;165774:902::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;165774:902:0;;:::i;183275:201::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;183275:201:0;-1:-1:-1;;;;;183275:201:0;;:::i;168721:170::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;168721:170:0;-1:-1:-1;;;;;168721:170:0;;:::i;184255:152::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;184255:152:0;-1:-1:-1;;;;;184255:152:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;178539:197;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;178539:197:0;;-1:-1:-1;;;;;178539:197:0;;;;;;;;:::i;165436:111::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;165436:111:0;;:::i;174484:1388::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;174484:1388:0;;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;174484:1388:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;174484:1388:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;174484:1388:0;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;174484:1388:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;174484:1388:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;174484:1388:0;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;174484:1388:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;174484:1388:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;174484:1388:0;;-1:-1:-1;174484:1388:0;-1:-1:-1;174484:1388:0;:::i;167771:120::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;167771:120:0;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;167771:120:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;167771:120:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;167771:120:0;;-1:-1:-1;167771:120:0;-1:-1:-1;167771:120:0;:::i;170447:3425::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;170447:3425: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;170447:3425:0;;;;;;;;;;;;;;;;;;185016:122;;;:::i;178919:170::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;178919:170:0;;:::i;182804:152::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;182804:152:0;;-1:-1:-1;;;;;182804:152:0;;;;;;;;:::i;184691:120::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;184691:120:0;-1:-1:-1;;;;;184691:120:0;;:::i;179762:103::-;;;:::i;179235:95::-;;;:::i;182110:388::-;-1:-1:-1;;;;;182313:23:0;;182195:14;182313:23;;;:15;:23;;;;;182195:14;;;;;;182358:19;182313:23;182358:12;:19::i;:::-;:59;;182416:1;182358:59;;;182395:8;;182380:33;;:4;;182405:7;182380:33;:14;:33;:::i;:::-;182349:68;;182471:19;182484:5;182471:12;:19::i;:::-;182110:388;;182428:62;;-1:-1:-1;182428:62:0;-1:-1:-1;182110:388:0;-1:-1:-1;;;;182110:388:0:o;166943:128::-;167017:46;167024:10;167036;167048:7;167057:5;;167017:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;167017:6:0;;-1:-1:-1;;;167017:46:0:i;:::-;166943:128;;;:::o;167391:137::-;167481:39;167488:10;167500:3;167505:7;167514:5;;167481:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;167481:6:0;;-1:-1:-1;;;167481:39:0:i;:::-;167391:137;;;;:::o;157172:346::-;156619:10;;;;;;;;;-1:-1:-1;;;;;156619:10:0;-1:-1:-1;;;;;156619:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;156619:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;156619:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;156619:29:0;156650:31;;;;;;;;;;;;;156619:29;156650:31;;;;-1:-1:-1;;;;;156605:43:0;:10;:43;156597:85;;;;-1:-1:-1;;;;;156597: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;156597:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;157277:31:0;;;;;;157302:4;157277:31;;;;;;157259:15;;-1:-1:-1;;;;;157277:16:0;;;;;:31;;;;;;;;;;;;;;;:16;:31;;;5:2:-1;;;;30:1;27;20:12;5:2;157277:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;157277:31:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;157277:31:0;157340:32;;;;;;;;;;;;;157277:31;157340:32;;;157277:31;;-1:-1:-1;157327:11:0;157319:54;;;;-1:-1:-1;;;;;157319:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;157319:54:0;-1:-1:-1;157392:33:0;-1:-1:-1;;;;;157392:19:0;;157412:3;157417:7;157392:33;:19;:33;:::i;:::-;157427:32;;;;;;;;;;;;;;;;;157384:76;;;;;-1:-1:-1;;;;;157384:76:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;157384:76:0;-1:-1:-1;157476:34:0;;;-1:-1:-1;;;;;157476:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;156693:1;157172:346;;:::o;152258:96::-;152306:10;152336;-1:-1:-1;;;;;152336:10:0;152258:96;:::o;180796:121::-;180859:7;180886:23;180902:6;180886:15;:23::i;:::-;180879:30;;180796:121;;;;:::o;169157:249::-;151793:17;:15;:17::i;:::-;-1:-1:-1;;;;;151771:40:0;:10;-1:-1:-1;;;;;151771:40:0;;151813:32;;;;;;;;;;;;;;;;;151763:83;;;;;-1:-1:-1;;;;;151763:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;151763:83:0;-1:-1:-1;169255:11:0;;169251:148;;169283:48;169309:6;169317:7;169326:4;169283:25;:48::i;:::-;169351:36;;;;;;;;-1:-1:-1;;;;;169351:36:0;;;;;;;;;;;;;169251:148;169157:249;;:::o;176522:1661::-;176631:4;151793:17;:15;:17::i;:::-;-1:-1:-1;;;;;151771:40:0;:10;-1:-1:-1;;;;;151771:40:0;;151813:32;;;;;;;;;;;;;;;;;151763:83;;;;;-1:-1:-1;;;;;151763:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;151763:83:0;-1:-1:-1;176652:12:0;176648:56;;-1:-1:-1;176688:4:0;176681:11;;176648:56;-1:-1:-1;;;;;176780:23:0;;176716:17;176780:23;;;:15;:23;;;;;176746:1;176736:11;;;176846:35;176780:23;176846:28;:35::i;:::-;176814:67;;176892:41;176936:54;176972:5;176979:10;176936:35;:54::i;:::-;176892:98;-1:-1:-1;177179:34:0;177216:60;:21;176892:98;177216:60;:25;:60;:::i;:::-;177179:97;;177301:26;177291:7;:36;177287:81;;;177351:5;177344:12;;;;;;;;;177287:81;177774:21;177764:7;:31;177760:267;;;177910:31;;;177956:59;177983:6;177910:31;178007:7;177956:26;:59::i;:::-;177760:267;;178049:8;;178037:49;;:4;;178059:10;178071:7;178049:8;178037:49;:11;:49;:::i;:::-;178104;;;;;;;;;;;;;;;-1:-1:-1;;;;;178104:49:0;;;;;;;;;;;178171:4;178164:11;;;;;;;151857:1;176522:1661;;;;;:::o;169541:227::-;151793:17;:15;:17::i;:::-;-1:-1:-1;;;;;151771:40:0;:10;-1:-1:-1;;;;;151771:40:0;;151813:32;;;;;;;;;;;;;;;;;151763:83;;;;;-1:-1:-1;;;;;151763:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;151763:83:0;-1:-1:-1;169621:11:0;;169617:144;;169649:54;159383:42;169689:7;169698:4;169649:25;:54::i;:::-;169723:26;;;;;;;;;;;;;;;;;169617:144;169541:227;:::o;183762:270::-;-1:-1:-1;;;;;183922:23:0;;183833:14;183922:23;;;:15;:23;;;;;:43;;;183984:14;184000:23;;;;;;;183762:270;;;:::o;185278:87::-;185328:4;185278:87;:::o;181374:182::-;181432:14;181448:17;181467:14;181483:27;181530:18;181541:6;181530:10;:18::i;:::-;181523:25;;;;;;;;181374:182;;;;;:::o;179512:117::-;179585:11;;:36;;;;;;179615:4;179585:36;;;;;;179558:7;;-1:-1:-1;;;;;179585:11:0;;:21;;:36;;;;;;;;;;;;;;:11;:36;;;5:2:-1;;;;30:1;27;20:12;5:2;179585:36:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;179585:36:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;179585:36:0;;-1:-1:-1;179512:117:0;:::o;180108:134::-;180177:7;180204:30;180226:7;180204:21;:30::i;168266:266::-;168389:10;-1:-1:-1;;;;;168389:20:0;;;:54;;;;-1:-1:-1;168431:11:0;;-1:-1:-1;;;;;168413:30:0;;;168431:11;;168413:30;168389:54;168445:31;;;;;;;;;;;;;;;;;168381:96;;;;;-1:-1:-1;;;;;168381:96:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;168381:96:0;;168488:36;168495:5;168502;168509:7;168518:5;;168488:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;168488:6:0;;-1:-1:-1;;;168488:36:0:i;:::-;168266:266;;;;;:::o;165774:902::-;165831:13;165847:20;:18;:20::i;:::-;165916:10;165878:19;165900:27;;;:15;:27;;;;;165831:36;;-1:-1:-1;165970:35:0;165900:27;165970:28;:35::i;:::-;165938:67;-1:-1:-1;166016:26:0;166045:12;;:46;;166084:7;166045:46;;;166060:21;166045:46;166016:75;;166131:1;166110:18;:22;166134:25;;;;;;;;;;;;;;;;;166102:58;;;;;-1:-1:-1;;;;;166102:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;166102:58:0;-1:-1:-1;166224:33:0;;;;;;;;;;;;;;;;;166179:43;;;;166171:87;;;;-1:-1:-1;;;;;166171:87:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;166171:87:0;-1:-1:-1;166367:42:0;;;166337:27;166447:28;166468:6;166447:20;:28::i;:::-;166420:55;-1:-1:-1;166494:24:0;;;:67;;;166545:16;166522:19;:39;;166494:67;166563:33;;;;;;;;;;;;;;;;;166486:111;;;;;-1:-1:-1;;;;;166486:111:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;166486:111:0;;166610:58;166637:10;166649:18;166610:26;:58::i;:::-;165774:902;;;;;;;:::o;183275:201::-;-1:-1:-1;;;;;183389:23:0;;183347:7;183389:23;;;:15;:23;;;;;183430:38;183389:23;183430:31;:38::i;168721:170::-;168793:13;168809:20;:18;:20::i;:::-;168793:36;;168840:43;168868:6;168876;168840:27;:43::i;184255:152::-;-1:-1:-1;;;;;184354:23:0;184328:6;184354:23;;;:15;:23;;;;;;;;:45;;;;;184255:152::o;178539:197::-;151793:17;:15;:17::i;:::-;-1:-1:-1;;;;;151771:40:0;:10;-1:-1:-1;;;;;151771:40:0;;151813:32;;;;;;;;;;;;;;;;;151763:83;;;;;-1:-1:-1;;;;;151763:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;151763:83:0;-1:-1:-1;;;;;;178657:23:0;;;;178635:19;178657:23;;;:15;:23;;;;;;;;178691:27;:37;;-1:-1:-1;;178691:37:0;;;;;;;;;;;178539:197::o;165436:111::-;165491:48;165507:10;165519:7;165528:10;165491:15;:48::i;174484:1388::-;174683:7;151793:17;:15;:17::i;:::-;-1:-1:-1;;;;;151771:40:0;:10;-1:-1:-1;;;;;151771:40:0;;151813:32;;;;;;;;;;;;;;;;;151763:83;;;;;-1:-1:-1;;;;;151763:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;151763:83:0;-1:-1:-1;174757:35:0;;;;;;;;;;;;;;;;;174716:39;;;174708:85;;;;-1:-1:-1;;;;;174708:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;174708:85:0;-1:-1:-1;174854:36:0;;;;;;;;;;;;;;;;;174812:40;;;174804:87;;;;-1:-1:-1;;;;;174804:87:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;174804:87:0;-1:-1:-1;174934:1:0;174924:11;;174904:17;;174982:848;175002:18;;;174982:848;;;175042:20;175065:14;;175080:1;175065:17;;;;;;;;;;;;;175042:40;;175097:20;175120:7;;175128:1;175120:10;;;;;;;;;;;;;;;;-1:-1:-1;;;;;175120:10:0;175145:19;175167:29;;;:15;:29;;;;;;;175233:19;;;;175120:10;;-1:-1:-1;175167:29:0;175233:37;;-1:-1:-1;175257:12:0;175233:23;:37::i;:::-;175211:19;;;:59;175470:15;;175486:1;175470:18;;;;;;;;;;;;;;175466:353;;175514:48;;;;;;;;-1:-1:-1;;;;;175514:48:0;;;;;;;;;;;;;175466:353;;;175621:33;:15;175641:12;175621:33;:19;:33;:::i;:::-;175685:8;;175603:51;;-1:-1:-1;175673:54:0;;:4;;175695:10;175707:12;175685:8;175673:54;:11;:54;:::i;:::-;175751:52;;;;;;;;;;;;;;;-1:-1:-1;;;;;175751:52:0;;;;;;;;;;;175466:353;-1:-1:-1;;;175022:3:0;;174982:848;;;-1:-1:-1;175849:15:0;174484:1388;-1:-1:-1;;;;;;;;;174484:1388:0:o;167771:120::-;167847:36;167856:10;167868:7;167877:5;;167847:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;167847:8:0;;-1:-1:-1;;;167847:36:0:i;170447:3425::-;170528:23;170553:14;151793:17;:15;:17::i;:::-;-1:-1:-1;;;;;151771:40:0;:10;-1:-1:-1;;;;;151771:40:0;;151813:32;;;;;;;;;;;;;;;;;151763:83;;;;;-1:-1:-1;;;;;151763:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;151763:83:0;;170580:30;;:::i;:::-;170613:26;;;;;;;;;;;;170631:7;;170613:26;;;;170631:7;;170613:26;170631:7;170613:26;1:33:-1;99:1;81:16;;74:27;;;;-1:-1;170613:17:0;;-1:-1:-1;;170613:26:0:i;:::-;170580:59;;170673:11;:32;;;170659:47;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;170659:47:0;-1:-1:-1;171290:1:0;171266:21;;;:25;170650:56;-1:-1:-1;171261:2604:0;171316:11;:32;;;171307:6;:41;:89;;;;;159554:2;171352:11;:21;;;:44;171307:89;171261:2604;;;171463:25;171490:31;171525:24;171537:11;171525;:24::i;:::-;171462:87;;-1:-1:-1;171462:87:0;-1:-1:-1;171571:9:0;171566:2288;171590:8;:15;171586:1;:19;:64;;;;;171618:11;:32;;;171609:6;:41;171586:64;171566:2288;;;171800:20;171823:17;:30;171841:8;171850:1;171841:11;;;;;;;;;;;;;;;;;;;171823:30;;;;;;;;;;;;;-1:-1:-1;171823:30:0;;;;-1:-1:-1;;;;;171823:30:0;171894:29;;;:15;:29;;;;;;172102:27;;;;171823:30;172078:19;;;171823:30;;-1:-1:-1;171894:29:0;;172078:52;;;:23;:52;:::i;:::-;172051:79;;172386:41;172430:66;172466:5;172473:11;:18;;;172494:1;172473:22;172430:35;:66::i;:::-;172386:110;;172640:28;172671:14;172686:1;172671:17;;;;;;;;;;;;;;172640:48;;172735:16;172711:20;:40;172707:1132;;173141:29;173173:59;:20;173198:33;173173:59;:24;:59;:::i;:::-;173141:91;;173283:16;173259:21;:40;173255:281;;;173410:102;173437:12;173470:21;173451:16;:40;173493:11;:18;;;173410:26;:102::i;:::-;173660:16;173638:5;:19;;:38;;;;173718:12;173699:6;173706:8;;;;;;173699:16;;;;;;;;;;;;;:31;-1:-1:-1;;;;;173699:31:0;;;-1:-1:-1;;;;;173699:31:0;;;;;173777:12;-1:-1:-1;;;;;173758:61:0;;173791:11;:27;;;173758:61;;;;;;;;;;;;;;;;;;172707:1132;;-1:-1:-1;;171652:3:0;;;;;-1:-1:-1;171566:2288:0;;-1:-1:-1;;171566:2288:0;;-1:-1:-1;;;171412:21:0;;;:23;;;;;;171261:2604;;;151857:1;170447:3425;;;:::o;185016:122::-;185107:23;;185016:122;:::o;178919:170::-;151357:17;:15;:17::i;:::-;-1:-1:-1;;;;;151343:31:0;:10;-1:-1:-1;;;;;151343:31:0;;151376:32;;;;;;;;;;;;;;;;;151335:74;;;;;-1:-1:-1;;;;;151335:74:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;151335:74:0;;179028:53;179056:24;179028:27;:53::i;182804:152::-;182886:7;182913:35;182932:6;182940:7;182913:18;:35::i;:::-;182906:42;;182804:152;;;;;:::o;184691:120::-;-1:-1:-1;;;;;184777:23:0;184750:7;184777:23;;;:15;:23;;;;;:26;;184691:120::o;179762:103::-;179815:7;179842:15;:4;:13;:15::i;:::-;179835:22;;179762:103;:::o;179235:95::-;179310:11;;-1:-1:-1;;;;;179310:11:0;179235:95;:::o;198762:113::-;198853:9;:14;;;198762:113::o;30990:165::-;31079:7;31106:41;31116:4;21814:1;31135:4;31141:5;31106:9;:41::i;:::-;31099:48;30990:165;-1:-1:-1;;;;30990:165:0:o;201340:291::-;201494:23;;;;201537:20;;;;201590:26;;;;:33;201494:23;;201340:291::o;191458:740::-;191583:25;;;;;;;;;;;;;;;;;191570:11;191562:47;;;;-1:-1:-1;;;;;191562:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;191562:47:0;;191620:48;191646:6;191654:7;191663:4;191620:25;:48::i;:::-;191904:38;191884:16;:5;:14;:16::i;:::-;:58;;;191880:130;;;191959:39;191975:6;191983:7;191992:5;191959:15;:39::i;:::-;192034:6;-1:-1:-1;;;;;192027:55:0;;192042:7;192051:23;192067:6;192051:15;:23::i;:::-;192076:5;192027: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;192027:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;192101:11;;:59;;-1:-1:-1;;;;;192101:11:0;192130:5;192145:4;192152:7;192101:59;:28;:59;:::i;:::-;192162:27;;;;;;;;;;;;;;;;;192093:97;;;;;-1:-1:-1;;;;;192093:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;1908:320:0;2041:105;;;-1:-1:-1;;;;;2041:105:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;2041:105:0;;;;;;;;25:18:-1;;61:17;;2041:105:0;182:15:-1;2078:17:0;179:29:-1;160:49;;1992:4:0;;2164:56;2194:6;2041:105;2164:21;:56::i;:::-;2157:63;1908:320;-1:-1:-1;;;;;1908:320:0:o;195757:243::-;195821:7;195842:14;195858:17;195879:27;195910:18;195921:6;195910:10;:18::i;:::-;195841:87;;;;;;;195946:46;195972:19;195946:21;195960:6;195946:9;:13;;:21;;;;:::i;:::-;:25;:46;:25;:46;:::i;153652:140::-;153702:15;153753:10;;;;;;;;;-1:-1:-1;;;;;153753:10:0;-1:-1:-1;;;;;153753:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;194126:862:0;194529:12;194525:51;;194558:7;;194525:51;-1:-1:-1;;;;;194610:23:0;;194588:19;194610:23;;;:15;:23;;;;;194644:337;;;;194699:22;;;;:35;;194726:7;194699:35;:26;:35;:::i;:::-;194674:22;;;:60;194644:337;;;194786:5;:22;;;194775:7;:33;;194810:34;;;;;;;;;;;;;;;;;194767:78;;;;;-1:-1:-1;;;;;194767:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;194767:78:0;-1:-1:-1;194936:22:0;;:33;;;;;;;;;-1:-1:-1;;194126:862:0:o;197740:194::-;197823:7;197850:20;197863:6;197850:12;:20::i;:::-;:76;;197925:1;197850:76;;;197901:20;;;;197886:9;;197873:49;;197901:20;197873:23;;:4;;:23;:12;:23;:::i;:::-;:27;:49;:27;:49;:::i;199219:271::-;199427:23;;;;199325:7;;199383:26;;;;199427:34;;;;:23;;:34;:55;;199481:1;199427:55;;;199464:14;;199420:62;-1:-1:-1;;;199219:271:0:o;6665:175::-;6792:18;;;;;;;;;;;;;;;;;6725:7;;6757;;;;6783;;;;6775:36;;;;-1:-1:-1;;;;;6775:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;6775:36:0;-1:-1:-1;6831:1:0;6665:175;-1:-1:-1;;;6665:175:0:o;190300:766::-;-1:-1:-1;;;;;190427:23:0;;190405:19;190427:23;;;:15;:23;;;;;;;;;190499:25;;;190566:14;;190632:40;;;;;;;;;;;;;;;;;;;190427:23;;190499:25;;190566:14;190599:31;;;;190591:82;;;;-1:-1:-1;;;;;190591:82:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;190591:82:0;-1:-1:-1;190779:30:0;;;190820:33;;;190919:8;;190907:49;;:4;;190939:1;190929:11;;;;190802:7;;190907:49;:11;:49;:::i;:::-;191007:23;;;;190974:84;;;191007:23;;;;190974:84;;;;;;;;;;;;;;;;-1:-1:-1;;;;;190974:84:0;;;;;;;;;;;;;190300:766;;;;;;;:::o;26550:639::-;26680:12;;26694:24;;;;;;;;;;;;;;;;;;26673:19;;26665:54;;;;-1:-1:-1;;;;;26665:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;26665:54:0;;26813:17;26833:19;26841:4;26847;26833:7;:19::i;:::-;26813:39;;26863:16;26882:9;:57;;26918:21;:9;26932:6;26918:21;:13;:21;:::i;:::-;26882:57;;;26894:21;:9;26908:6;26894:21;:13;:21;:::i;:::-;26863:76;;26950:46;26955:4;21814:1;26974:4;26980:5;26987:8;26950:4;:46::i;:::-;27132:49;27144:4;27150;27156:5;27163:6;27171:9;27132:11;:49::i;196478:346::-;-1:-1:-1;;;;;196650:23:0;;196537:14;196650:23;;;:15;:23;;;;;196537:14;;;;;;196695:19;196650:23;196695:12;:19::i;:::-;:48;;196742:1;196695:48;;;196730:8;;196717:22;;:4;;:22;:12;:22;:::i;:::-;196686:57;;196797:19;196810:5;196797:12;:19::i;:::-;196478:346;;196754:62;;-1:-1:-1;196754:62:0;;-1:-1:-1;196478:346:0;-1:-1:-1;;;196478:346:0:o;199754:534::-;199824:7;200148:11;200173:23;:21;:23::i;:::-;200162:34;;:7;:34;;;;200148:48;;200214:6;:66;;200256:24;:4;200272:7;200256:24;:15;:24;:::i;:::-;200214:66;;;200223:30;:4;200245:7;200223:30;:21;:30;:::i;152544:110::-;152592:6;152618:8;:6;:8::i;:::-;-1:-1:-1;;;;;152618:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;152618:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;130220:147:0;130289:7;130316:14;:12;:14::i;:::-;-1:-1:-1;;;;;130316:34:0;;130351:7;130316:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;130316:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;130316:43:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;130316:43:0;;130220:147;-1:-1:-1;;130220:147:0:o;187799:666::-;187888:13;187904:20;:18;:20::i;:::-;187888:36;;188006:43;188034:6;188042;188006:27;:43::i;:::-;-1:-1:-1;;;;;188125:23:0;;188062:17;188125:23;;;:15;:23;;;;;188197:25;;;188250:14;;188091:1;188082:10;;;188125:23;188197:25;188250:27;;188269:7;188250:27;:18;:27;:::i;:::-;188233:44;;188288:23;;;:36;;-1:-1:-1;;188288:36:0;;;;;;;188347:8;;188335:49;;:4;;188288:36;188369:7;-1:-1:-1;188335:11:0;:49::i;:::-;188402:55;;;;;;;;;;;;;;;;-1:-1:-1;;;;;188402:55:0;;;;;;;;;;;187799:666;;;;;;:::o;198265:279::-;198351:7;198371:24;198398:23;:21;:23::i;:::-;198371:50;;198439:20;198452:6;198439:12;:20::i;:::-;:97;;198535:1;198439:97;;;198511:20;;;;198477:9;;198462:70;;198511:20;198462:44;;:4;;198488:17;198462:44;:14;:44;:::i;188847:1011::-;-1:-1:-1;;;;;188958:23:0;;188936:19;188958:23;;;:15;:23;;;;;189103;;;;189030:25;;;;189103:23;;189242:40;;;:81;;;189296:27;189286:37;;:7;:37;;;189242:81;189238:120;;;189340:7;;;;;189238:120;189399:14;;189606:23;;;;:35;;-1:-1:-1;;189606:35:0;;;189370:26;189652:18;;189681:59;;189707:6;;189399:14;;189681:25;:59::i;:::-;189758:92;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;189758:92:0;;;;;;;;;;;;;188847:1011;;;;;;:::o;185767:1679::-;185862:13;185878:20;:18;:20::i;:::-;185862:36;;185975:43;186003:6;186011;185975:27;:43::i;:::-;-1:-1:-1;;;;;186058:23:0;;186031:24;186058:23;;;:15;:23;;;;;:40;;;;186136:12;;:41;;186170:7;186136:41;;;186151:16;186136:41;186109:68;;186215:1;186196:16;:20;186218:25;;;;;;;;;;;;;;;;;186188:56;;;;;-1:-1:-1;;;;;186188:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;186188:56:0;-1:-1:-1;186301:31:0;;;;;;;;;;;;;;;;;186263:36;;;;186255:78;;;;-1:-1:-1;;;;;186255:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;186255:78:0;-1:-1:-1;186375:1:0;186366:10;;186387:54;186366:10;186424:16;186387:24;:54::i;:::-;-1:-1:-1;;;;;186474:23:0;;186452:19;186474:23;;;:15;:23;;;;;;186535:32;186556:10;186535:20;:32::i;:::-;186508:59;;186584:19;186597:5;186584:12;:19::i;:::-;186580:711;;;186859:8;;186822:21;;186846:22;;:4;;:22;:12;:22;:::i;:::-;186822:46;-1:-1:-1;186930:16:0;186891:35;186822:46;186909:16;186891:35;:17;:35;:::i;:::-;:55;;186948:30;;;;;;;;;;;;;;;;;186883:96;;;;;-1:-1:-1;;;;;186883:96:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;186883:96:0;-1:-1:-1;187006:8:0;;186994:57;;:4;;187016:10;187028:16;187046:4;186994:57;:11;:57;:::i;:::-;186580:711;;;;187130:30;;;;;;;;;;;;;;;;;187092:36;;;;187084:77;;;;-1:-1:-1;;;;;187084:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;187084:77:0;-1:-1:-1;187187:41:0;:4;187199:10;187211:16;187187:41;:11;:41;:::i;:::-;187176:52;;;:8;187243:27;;;:17;:27;;;;;:36;;;;-1:-1:-1;;;;;187243:36:0;;;;;186580:711;187303:58;187329:6;187337:16;187355:5;187303:25;:58::i;:::-;187377:61;;;;;;;;;;;;;;-1:-1:-1;;;;;187377:61:0;;;;;;;;;;;;;;;;;;;;;;185767:1679;;;;;;;;;:::o;6412:177::-;6472:7;6506:2;6500;:8;;6510:19;;;;;;;;;;;;;;;;;6492:38;;;;;-1:-1:-1;;;;;6492:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;6492:38:0;-1:-1:-1;;6553:7:0;;;6412:177::o;192497:1251::-;192609:25;;;;;;;;;;;;;;;;;192596:11;192588:47;;;;-1:-1:-1;;;;;192588:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;192588:47:0;;193136:24;193163:23;:21;:23::i;:::-;-1:-1:-1;;;;;193288:23:0;;193257:28;193288:23;;;:15;:23;;;;;;;;:45;;193136:50;;-1:-1:-1;193288:45:0;;193352:26;;;:71;;;193406:17;193382:41;;:21;:41;;;193352:71;193425:22;;;;;;;;;;;;;;;;;193344:104;;;;;-1:-1:-1;;;;;193344:104:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;193344:104:0;;193461:54;193489:6;193497:17;193461:27;:54::i;:::-;193528:49;193554:6;193562:7;193571:5;193528:25;:49::i;:::-;193602:6;-1:-1:-1;;;;;193593:57:0;;193610:7;193619:23;193635:6;193619:15;:23::i;:::-;193644:5;193593: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;193593:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;193669:11;;:41;;-1:-1:-1;;;;;193669:11:0;193694:6;193702:7;193669:41;:24;:41;:::i;:::-;193712:27;;;;;;;;;;;;;;;;;193661:79;;;;;-1:-1:-1;;;;;193661:79:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;193661:79:0;;192497:1251;;;;;:::o;203059:608::-;203135:18;;:::i;:::-;203189:10;;;;203166:13;203238:28;203189:10;203238:20;:28::i;:::-;203211:55;;203286:373;;;;;;;;203337:7;203345:1;203337:10;;;;;;;;;;;;;;;;203286:373;;203374:10;;;;203286:373;;;;;;;;;;;;203444:10;;;;203286:373;;;;;203491:10;;;;203286:373;;;;;203538:10;;;;203286:373;;;;;;203580:40;203374:10;203616:1;203608:10;;;;203580:16;;:40;:20;:40;:::i;:::-;203286:373;;203646:1;203286:373;;;;;203279:380;203059:608;-1:-1:-1;;;;203059:608:0:o;202004:458::-;202076:20;202098:31;202166:288;202205:7;:22;;;202242:7;:17;;;202274:7;:14;;;202303:7;:22;;;202340:7;:28;;;202383:7;:28;;;202426:7;:17;;;202166:4;:24;;:288;;;;;;;;;;:::i;:::-;202142:312;;;;-1:-1:-1;202004:458:0;-1:-1:-1;;202004:458:0:o;153360:115::-;153410:7;153437:10;;;;;;;;;-1:-1:-1;;;;;153437:10:0;-1:-1:-1;;;;;153437:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;195189:332:0;195318:36;;;;;;;;;;;;;;;;;195288:28;195280:75;;;;-1:-1:-1;;;;;195280:75:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;195280:75:0;-1:-1:-1;195402:23:0;;195371:81;;;;;;;;;;;;;;;;;;;;;;;;195463:23;:50;195189:332::o;197130:233::-;-1:-1:-1;;;;;197255:23:0;;197213:7;197255:23;;;:15;:23;;;;;197296:19;197255:23;197296:12;:19::i;:::-;:59;;197354:1;197296:59;;;197333:8;;197318:33;;:4;;197343:7;197318:33;:14;:33;:::i;29129:175::-;29189:7;29209:17;29229:15;29239:4;29229:9;:15::i;:::-;29209:35;;29262:34;29270:4;29276:9;22162:1;29262:7;:34::i;31898:175::-;32003:7;32030:18;;;:10;;;:18;;;;;;;;:24;;;;;;;;:35;;32059:5;32030:35;:28;:35;:::i;10816:217::-;10877:13;10922:1;10907:5;:12;:16;10903:65;;;-1:-1:-1;10954:1:0;10940:16;;10903:65;-1:-1:-1;11018:4:0;11007:16;11001:23;;10989:37::o;2416:378::-;2572:136;;;-1:-1:-1;;;;;2572:136:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;2572:136:0;;;;;;;;25:18:-1;;61:17;;2572:136:0;182:15:-1;2609:28:0;179:29:-1;160:49;;2519:4:0;;2726:60;2609:6;2572:136;2726:21;:60::i;:::-;2719:67;2416:378;-1:-1:-1;;;;;;2416:378:0:o;3318:1346::-;3405:4;3422:8;3482:4;3476:11;3913:4;3841:3;3789:9;3783:16;3741:4;3730:9;3726:20;3675:1;3625:5;3567:3;3544:423;3986:14;;3983:2;;4098:14;4186:57;;;;4325:4;4320:189;;;;4091:519;;4186:57;4223:1;4216:8;;4186:57;;4320:189;4488:1;4482:3;4476:10;4473:17;4466:24;;4091:519;;3983:2;-1:-1:-1;4653:3:0;;3318:1346;-1:-1:-1;;;;3318:1346:0:o;30558:140::-;30631:7;30658:32;30666:4;21814:1;30685:4;30658:7;:32::i;37132:163::-;37244:18;;;;:10;;;:18;;;;;;;;:24;;;;;;;;:43;;37273:5;37280:6;37244:43;:28;:43;:::i;33698:1952::-;-1:-1:-1;;33876:4:0;33817:12;33915:15;33925:4;33915:9;:15::i;:::-;33891:39;-1:-1:-1;33976:1:0;33941:1419;33988:13;33979:5;:22;33941:1419;;21626:1;34554:22;;;;;35078:18;;;;35142:17;35162:33;35170:4;35176:5;35078:18;35162:7;:33::i;:::-;35142:53;;35210:16;35229:9;:57;;35265:21;:9;35279:6;35265:21;:13;:21;:::i;:::-;35229:57;;;35241:21;:9;35255:6;35241:21;:13;:21;:::i;:::-;35210:76;;35301:47;35306:4;35312:5;35319:11;35332:5;35339:8;35301:4;:47::i;:::-;-1:-1:-1;;34003:7:0;;33941:1419;;;;35554:9;35553:10;:65;;;;35612:6;35567:41;35575:4;35581:13;35596:11;35567:7;:41::i;:::-;:51;;35553:65;35620:21;;;;;;;;;;;;;;;;;35545:97;;;;;-1:-1:-1;;;;;35545:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;35545:97:0;;33698:1952;;;;;;;;:::o;152818:121::-;152874:6;152900:8;:6;:8::i;:::-;-1:-1:-1;;;;;152900:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;29645:215:0;29721:7;29741:17;29761:30;29779:4;29785:5;29761:17;:30::i;:::-;29741:50;;29809:43;29819:4;29825:9;22162:1;29846:5;29809:9;:43::i;30176:227::-;30258:7;30278:17;30298:30;30316:4;30322:5;30298:17;:30::i;:::-;30278:50;;30346:49;30362:4;30368:9;22162:1;30389:5;30346:15;:49::i;200556:352::-;200648:33;200684:30;200706:7;200684:21;:30::i;:::-;200648:66;-1:-1:-1;200725:29:0;200757:38;200648:66;200787:7;200757:38;:29;:38;:::i;:::-;200725:70;;200839:23;;200814:21;:48;;200864:35;;;;;;;;;;;;;;;;;200806:94;;;;;-1:-1:-1;;;;;200806:94:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;24347:779:0;24666:14;;;;;;;24430:7;;24691:38;24666:4;:14;24723:5;24691:20;:38::i;:::-;24958:10;;24954:144;;24985:43;24990:4;21814:1;25009:3;25014:5;25021:6;24985:4;:43::i;:::-;25043;25055:4;25061:3;25066:5;25073:6;25081:4;25043:11;:43::i;45263:132::-;45326:7;45120:5;45353:23;:4;45362:13;;;45353:23;:8;:23;:::i;:::-;:34;;;;;;;45263:132;-1:-1:-1;;;45263:132:0:o;47140:1083::-;47505:26;47533:31;47583:11;47596:12;47612:98;47633:4;47639:7;47648:15;47665:21;47688;47612:20;:98::i;:::-;47582:128;;;;47721:25;47749:201;47792:15;47822:10;47847:19;47881:21;47917:3;47935:4;47749:28;:201::i;:::-;47721:229;-1:-1:-1;47993:30:0;:4;47721:229;48015:7;47993:30;:11;:30;:::i;:::-;48064:21;;48044:16;;48087:32;;;;;;;;;;;;;;;;;47963:60;;-1:-1:-1;47963:60:0;;-1:-1:-1;48044:41:0;48036:84;;;;-1:-1:-1;;;;;48036:84:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;48036:84:0;;48159:21;48139:9;:16;:41;48182:32;;;;;;;;;;;;;;;;;48131:84;;;;;-1:-1:-1;;;;;48131:84:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;48131:84:0;;47140:1083;;;;;;;;;;;;;;:::o;32708:117::-;32769:7;32796:21;:4;:11;;:19;:21::i;31379:158::-;31468:7;31495:18;;;:10;;;:18;;;;;;;;:24;;;;;;;;:34;;:32;:34::i;13731:133::-;13803:7;13830:26;13844:4;13850:5;13830:13;:26::i;12622:192::-;12738:19;;;;;;;;;;;;;;;;;11267:20;12715:21;;;12707:51;;;;-1:-1:-1;;;;;12707:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;12707:51:0;;12769:37;12777:4;12783:5;12798:6;12769:7;:37::i;33040:146::-;33123:7;33150:28;:11;;;33172:5;33150:28;:21;:28;:::i;32456:187::-;32567:7;32594:18;;;:10;;;:18;;;;;;;;:24;;;;;;;;:41;;32629:5;32594:41;:34;:41;:::i;35909:758::-;36008:21;36032:15;36042:4;36032:9;:15::i;:::-;36008:39;;36062;36078:13;36093:7;36062:15;:39::i;:::-;36058:602;;;36462:1;36446:17;;36426;36498:38;36506:4;36446:13;36426:17;36498:7;:38::i;:::-;36478:58;;36551:49;36556:4;36562:9;22162:1;36583:5;36590:9;36551:4;:49::i;:::-;36615:33;:11;;;36631:5;36638:9;36615:33;:15;:33;:::i;5384:460::-;5444:7;5688;5684:48;;-1:-1:-1;5719:1:0;5712:8;;5684:48;5756:7;;;5761:2;5756;:7;:2;5782:6;;;;;:12;5796:18;;;;;;;;;;;;;;;;;5774:41;;;;;-1:-1:-1;;;;;5774:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;48932:627:0;49197:11;;;49269:30;:4;49291:7;49269:30;:21;:30;:::i;:::-;49240:59;-1:-1:-1;49316:66:0;49360:21;49316:39;:15;49240:59;49316:39;:19;:39;:::i;:::-;:43;:66;:43;:66;:::i;:::-;49310:72;-1:-1:-1;49395:25:0;49423:42;:15;49443:21;49423:42;:19;:42;:::i;:::-;49395:70;-1:-1:-1;49483:68:0;49529:21;49483:41;49395:70;49505:18;49483:41;:21;:41;:::i;:68::-;49476:75;;48932:627;;;;;;;;;;:::o;50411:2144::-;50714:16;51032:14;51014:15;:32;51048:29;;;;;;;;;;;;;;;;;51006:72;;;;;-1:-1:-1;;;;;51006:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;51006:72:0;;51089:16;51126:14;51108:15;:32;51089:51;;51248:25;51290:21;51276:36;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;51276:36:0;-1:-1:-1;51248:64:0;-1:-1:-1;51328:24:0;51323:1199;51377:21;51358:16;:40;51323:1199;;;51849:84;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;51849:84:0;;;;;;;51839:95;;;;;52157:44;52192:8;51839:95;52192:8;52176:24;;;;52157:14;;52176:24;;52157:44;:18;:44;:::i;:::-;52128:8;52137:16;52128:26;;;;;;;;;;;;;;;;;:73;52300:16;52283:228;52322:1;52318;:5;:38;;;;;52341:8;52354:1;52350;:5;52341:15;;;;;;;;;;;;;;52327:8;52336:1;52327:11;;;;;;;;;;;;;;:29;52318:38;52283:228;;;52382:11;52396:8;52409:1;52405;:5;52396:15;;;;;;;;;;;;;;52382:29;;52448:8;52457:1;52448:11;;;;;;;;;;;;;;52430:8;52443:1;52439;:5;52430:15;;;;;;;;;;;;;:29;;;;;52492:3;52478:8;52487:1;52478:11;;;;;;;;;;;;;;;;;:17;-1:-1:-1;;;52358:3:0;52283:228;;;-1:-1:-1;;51400:18:0;;51323:1199;;;-1:-1:-1;52539:8:0;50411:2144;-1:-1:-1;;;;;;;;50411:2144:0:o;27875:1119::-;27982:21;28005:23;28071:1;28054:7;:14;:18;28074:27;;;;;;;;;;;;;;;;;28046:56;;;;;-1:-1:-1;;;;;28046:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;28046:56:0;;28249:13;28265:29;28282:4;28288:5;28265:16;:29::i;:::-;28249:45;;28396:1;28388:5;:9;:48;;;;;28409:7;28434:1;28417:7;:14;:18;28409:27;;;;;;;;;;;;;;28401:5;:35;28388:48;28438:26;;;;;;;;;;;;;;;;;28380:85;;;;;-1:-1:-1;;;;;28380:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;28380:85:0;;28534:17;28554:30;28572:4;28578:5;28554:17;:30::i;:::-;28534:50;;28595:32;;:::i;:::-;28630:53;;;;;;;;;;;;;;;;;28650:16;:9;28664:1;28650:16;:13;:16;:::i;:::-;28630:53;;;;22162:1;28630:53;;;;28678:1;28630:53;;;;28681:1;28630:53;;;28595:88;;28814:14;28831:7;:14;28814:31;;28877:6;28863:21;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;28863:21:0;;28856:28;;28918:6;28904:21;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;28904:21:0;;28895:30;;28936:50;28944:4;28950:7;28959:12;28973:4;28979:6;28936:7;:50::i;:::-;27875:1119;;;;;;;;;;:::o;13003:246::-;13102:19;;13065:7;;13136:10;;13132:89;;13178:4;:12;;13200:1;13191:6;:10;13178:24;;;;;;;;;;;;;;;;;:30;;;;;;;-1:-1:-1;13163:46:0;;-1:-1:-1;13163:46:0;13132:89;-1:-1:-1;13240:1:0;;13003:246;-1:-1:-1;;13003:246:0:o;17648:1576::-;17852:19;;17729:7;;17886:11;17882:52;;17921:1;17914:8;;;;;17882:52;18116:23;;-1:-1:-1;;18082:10:0;;;18116:4;;18082:10;;18116:23;;;;;;;;;;;;;;;:28;;;;;18107:37;;;;18103:115;;18176:4;:12;;18189:9;18176:23;;;;;;;;;;;;;;;;;:29;;;;;;;-1:-1:-1;18161:45:0;;-1:-1:-1;;18161:45:0;18103:115;18360:4;:12;;18373:1;18360:15;;;;;;;;;;;;;;;;;:20;;;;;18352:28;;;;18348:69;;;18404:1;18397:8;;;;;;18348:69;18511:11;18552:9;18574:591;18588:3;18581:4;:10;18574:591;;;18776:17;;18728:1;18710:10;;;18723:1;18710:14;18709:20;;18695:11;;18776:4;;18709:20;;18776:17;;;;;;;;;;;;;;;18825:15;;18776:17;;-1:-1:-1;18825:15:0;;;;;18861;;;-1:-1:-1;18857:297:0;;;18903:3;18897:9;;18857:297;;;18940:7;18932:15;;:5;:15;;;18928:226;;;19064:1;19058:3;:7;19051:14;;18928:226;;;-1:-1:-1;19121:16:0;;;;;;;-1:-1:-1;19106:32:0;;-1:-1:-1;;;;;19106:32:0;18928:226;18574:591;;;;;;19192:4;:12;;19205:3;19192:17;;;;;;;;;;;;;;;;;:23;;;;;;;17648:1576;-1:-1:-1;;;;;;;17648:1576:0:o;14965:906::-;15070:19;;15104:11;;;:65;;-1:-1:-1;15132:19:0;;15119:50;;;;:4;;-1:-1:-1;;15132:23:0;;;15119:37;;;;;;;;;;;;;;;:42;;;:50;15104:65;15100:764;;;15376:25;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;39:1;23:18;;45:23;;15358:12:0;:44;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;15358:44:0;;;;;;;;;;;;;15100:764;;;15658:36;15697:4;:12;;15719:1;15710:6;:10;15697:24;;;;;;;;;;;;;;;;;;15753:22;;15777:27;;;;;;;;;;;;;;;;;;;;15697:24;;-1:-1:-1;15753:22:0;15744:31;;;15753:22;;15744:31;15736:69;;;;-1:-1:-1;;;;;15736:69:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;15736:69:0;-1:-1:-1;15820:32:0;;;;;;;;;;;;;;14965:906;;;;:::o;14310:148::-;14388:7;14415:35;14438:4;14444:5;14415:22;:35::i;42254:815::-;42342:4;;42828:34;:14;21626:1;42828:34;:18;:34;:::i;:::-;-1:-1:-1;;42888:20:0;;43041:14;;43040:21;;;-1:-1:-1;;42254:815:0;;;;:::o;5967:319::-;6027:7;6060:1;6055:2;:6;6063:14;;;;;;;;;;;;;;;;;6047:31;;;;;-1:-1:-1;;;;;6047:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;6047:31:0;;6147:9;6164:2;6159;:7;;;;;;;5967:319;-1:-1:-1;;;;5967:319:0:o;38346:3467::-;38638:13;;;;38598:37;;38638:33;;21626:1;38638:33;:17;:33;:::i;:::-;38598:73;-1:-1:-1;38689:19:0;38684:3122;21575:2;38714:11;:22;38684:3122;;;38852:7;:14;38829:7;:19;;;:37;38825:83;;38887:5;;38825:83;39797:17;;;;39774:20;;39797:67;;39819:44;;;39797:67;:21;:67;:::i;:::-;39774:90;;39879:22;39904:64;39920:4;39926:7;:13;;;39941:12;39955:7;:12;;;39904:15;:64::i;:::-;39879:89;;40207:23;40233:40;40258:14;40233:7;:20;;;:24;;:40;;;;:::i;:::-;40207:66;;40288:29;40320:74;40348:7;40357;:19;;;40378:15;40320:27;:74::i;:::-;40288:106;-1:-1:-1;40510:25:0;;40506:1163;;40779:13;;;;40775:720;;40832:116;40847:7;:19;;;40868:21;40891:12;40905:11;40918:14;40934:13;40832:14;:116::i;:::-;40775:720;;;40997:35;;:::i;:::-;41035:350;;;;;;;;41074:7;:12;;;41035:350;;;;;;41129:1;41113:7;:13;;;:17;41035:350;;;;41257:12;41035:350;;;;41296:7;:19;;;41035:350;;;;41342:7;:20;;;41035:350;;;40997:388;;41408:67;41416:4;41422:7;41431:15;41448:11;41461:13;41408:7;:67::i;:::-;40775:720;;41607:19;;;;:46;;41631:21;41607:46;:23;:46;:::i;:::-;41585:19;;;:68;40506:1163;-1:-1:-1;41756:20:0;;;:38;-1:-1:-1;;38738:13:0;;38684:3122;;16476:614;16689:19;;16566:7;;16723:11;16719:52;;16758:1;16751:8;;;;;16719:52;16852:19;;-1:-1:-1;;16799:10:0;;;16783:13;;16852:4;;16799:10;;16852:19;;;;;;;;;;;;;16820:51;;16882:126;16897:1;16889:5;:9;:36;;;;-1:-1:-1;16902:15:0;;:23;;;;:15;;:23;16889:36;16882:126;;;16977:19;;-1:-1:-1;;16942:7:0;;;;16977:4;;16942:7;;16977:19;;;;;;;;;;;;;16964:32;;16882:126;;;17027:15;;:23;;;;:15;;:23;:55;;17065:16;;;;;;;17027:55;;;17053:1;17020:62;16476:614;-1:-1:-1;;;;;;16476:614:0:o;43530:388::-;43660:7;43767:12;43790:87;43801:7;:14;43797:1;:18;:48;;;;;43832:13;43819:7;43827:1;43819:10;;;;;;;;;;;;;;:26;43797:48;43790:87;;;43862:3;;43790:87;;;43894:16;;;;;43530:388;-1:-1:-1;;;43530:388:0:o;44540:403::-;44800:9;44795:141;44819:6;44815:1;:10;44795:141;;;44872:4;44847:11;44867:1;44859:5;:9;44847:22;;;;;;;;;;;;;:29;;;;;44918:6;44891:13;44913:1;44905:5;:9;44891:24;;;;;;;;;;;;;;;;;:33;44827:3;;44795:141;;157628:46042;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;23915:156::-;23968:61;24027:1;23968:11;;;;22327:1;;23968:61;:15;:61;:::i;:::-;22162:1;24040:23;;23915:156::o
Swarm Source
bzzr://0f1569b86ba4df4896c73943c86f522b57715b54798a50aae9ef13dfef05753f
Loading...
Loading
Loading...
Loading
OVERVIEW
Aragon Court handles subjective disputes that require the judgment of human jurors. These jurors stake a token called ANJ which allows them to be drafted into juries and earn fees for successfully adjudicating disputes.Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.