Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 654 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Claim Fees | 15325313 | 886 days ago | IN | 0 ETH | 0.00097491 | ||||
Claim Fees | 15325313 | 886 days ago | IN | 0 ETH | 0.00097054 | ||||
Claim Fees | 13719723 | 1140 days ago | IN | 0 ETH | 0.01245041 | ||||
Claim Fees | 13146115 | 1230 days ago | IN | 0 ETH | 0.00219422 | ||||
Claim Fees | 13146115 | 1230 days ago | IN | 0 ETH | 0.00585202 | ||||
Claim Fees | 13146115 | 1230 days ago | IN | 0 ETH | 0.00585202 | ||||
Claim Fees | 13146114 | 1230 days ago | IN | 0 ETH | 0.00529177 | ||||
Claim Fees | 13146104 | 1230 days ago | IN | 0 ETH | 0.00900573 | ||||
Claim Fees | 13145553 | 1230 days ago | IN | 0 ETH | 0.00912749 | ||||
Claim Fees | 13020645 | 1249 days ago | IN | 0 ETH | 0.00126586 | ||||
Claim Fees | 13009743 | 1251 days ago | IN | 0 ETH | 0.00322923 | ||||
Claim Fees | 12991699 | 1253 days ago | IN | 0 ETH | 0.00881532 | ||||
Claim Fees | 12991699 | 1253 days ago | IN | 0 ETH | 0.00881532 | ||||
Claim Fees | 12970084 | 1257 days ago | IN | 0 ETH | 0.00267233 | ||||
Claim Fees | 12970084 | 1257 days ago | IN | 0 ETH | 0.00267233 | ||||
Claim Fees | 12970084 | 1257 days ago | IN | 0 ETH | 0.00267233 | ||||
Claim Fees | 12970084 | 1257 days ago | IN | 0 ETH | 0.0028428 | ||||
Claim Fees | 12803360 | 1283 days ago | IN | 0 ETH | 0.00101455 | ||||
Claim Fees | 12803360 | 1283 days ago | IN | 0 ETH | 0.00101455 | ||||
Claim Fees | 12803360 | 1283 days ago | IN | 0 ETH | 0.00101455 | ||||
Claim Fees | 12788995 | 1285 days ago | IN | 0 ETH | 0.00192112 | ||||
Claim Fees | 12788995 | 1285 days ago | IN | 0 ETH | 0.00192112 | ||||
Claim Fees | 12788994 | 1285 days ago | IN | 0 ETH | 0.00192112 | ||||
Claim Fees | 12788994 | 1285 days ago | IN | 0 ETH | 0.0022458 | ||||
Claim Fees | 12748307 | 1292 days ago | IN | 0 ETH | 0.00107134 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
CourtSubscriptions
Compiler Version
v0.5.8+commit.23d335f2
Optimization Enabled:
Yes with 5000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2019-11-28 */ /** * Commit sha: c7bf36f004a2b0e11d7e14234cea7853fd3a523a * GitHub repository: https://github.com/aragon/aragon-court * Tool used for the deploy: https://github.com/aragon/aragon-network-deploy **/ // File: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/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: ../../aragon-court/contracts/subscriptions/CourtSubscriptions.sol pragma solidity ^0.5.8; contract CourtSubscriptions is ControlledRecoverable, TimeHelpers, ISubscriptions { using SafeERC20 for ERC20; using SafeMath for uint256; using SafeMath64 for uint64; using PctHelpers for uint256; string private constant ERROR_SENDER_NOT_SUBSCRIBED = "CS_SENDER_NOT_SUBSCRIBED"; string private constant ERROR_GOVERNOR_SHARE_FEES_ZERO = "CS_GOVERNOR_SHARE_FEES_ZERO"; string private constant ERROR_TOKEN_TRANSFER_FAILED = "CS_TOKEN_TRANSFER_FAILED"; string private constant ERROR_PERIOD_DURATION_ZERO = "CS_PERIOD_DURATION_ZERO"; string private constant ERROR_FEE_AMOUNT_ZERO = "CS_FEE_AMOUNT_ZERO"; string private constant ERROR_FEE_TOKEN_NOT_CONTRACT = "CS_FEE_TOKEN_NOT_CONTRACT"; string private constant ERROR_PREPAYMENT_PERIODS_ZERO = "CS_PREPAYMENT_PERIODS_ZERO"; string private constant ERROR_OVERRATED_GOVERNOR_SHARE_PCT = "CS_OVERRATED_GOVERNOR_SHARE_PCT"; string private constant ERROR_RESUME_PRE_PAID_PERIODS_TOO_BIG = "CS_RESUME_PRE_PAID_PERIODS_BIG"; string private constant ERROR_NON_PAST_PERIOD = "CS_NON_PAST_PERIOD"; string private constant ERROR_JUROR_FEES_ALREADY_CLAIMED = "CS_JUROR_FEES_ALREADY_CLAIMED"; string private constant ERROR_JUROR_NOTHING_TO_CLAIM = "CS_JUROR_NOTHING_TO_CLAIM"; string private constant ERROR_PAYING_ZERO_PERIODS = "CS_PAYING_ZERO_PERIODS"; string private constant ERROR_PAYING_TOO_MANY_PERIODS = "CS_PAYING_TOO_MANY_PERIODS"; string private constant ERROR_LOW_RESUME_PERIODS_PAYMENT = "CS_LOW_RESUME_PERIODS_PAYMENT"; string private constant ERROR_DONATION_AMOUNT_ZERO = "CS_DONATION_AMOUNT_ZERO"; string private constant ERROR_COURT_HAS_NOT_STARTED = "CS_COURT_HAS_NOT_STARTED"; string private constant ERROR_SUBSCRIPTION_PAUSED = "CS_SUBSCRIPTION_PAUSED"; string private constant ERROR_SUBSCRIPTION_NOT_PAUSED = "CS_SUBSCRIPTION_NOT_PAUSED"; // Term 0 is for jurors on-boarding uint64 internal constant START_TERM_ID = 1; struct Subscriber { bool subscribed; // Whether or not a user has been subscribed to the Court bool paused; // Whether or not a user has paused the Court subscriptions uint64 lastPaymentPeriodId; // Identification number of the last period paid by a subscriber uint64 previousDelayedPeriods; // Number of delayed periods before pausing } struct Period { uint64 balanceCheckpoint; // Court term ID of a period used to fetch the total active balance of the jurors registry ERC20 feeToken; // Fee token corresponding to a certain subscription period uint256 feeAmount; // Amount of fees paid for a certain subscription period uint256 totalActiveBalance; // Total amount of juror tokens active in the Court at the corresponding period checkpoint uint256 collectedFees; // Total amount of subscription fees collected during a period mapping (address => bool) claimedFees; // List of jurors that have claimed fees during a period, indexed by juror address } // Duration of a subscription period in Court terms uint64 public periodDuration; // Permyriad of subscription fees that will be applied as penalty for not paying during proper period (‱ - 1/10,000) uint16 public latePaymentPenaltyPct; // Permyriad of subscription fees that will be allocated to the governor of the Court (‱ - 1/10,000) uint16 public governorSharePct; // ERC20 token used for the subscription fees ERC20 public currentFeeToken; // Amount of fees to be paid for each subscription period uint256 public currentFeeAmount; // Number of periods that can be paid in advance including the current period. Paying in advance has some drawbacks: // - Fee amount could increase, while pre-payments would be made with the old rate. // - Fees are distributed among jurors when the payment is made, so jurors activating after a pre-payment won't get their share of it. uint256 public prePaymentPeriods; // Number of periods a subscriber must pre-pay in order to resume his activity after pausing uint256 public resumePrePaidPeriods; // Total amount of fees accumulated for the governor of the Court uint256 public accumulatedGovernorFees; // List of subscribers indexed by address mapping (address => Subscriber) internal subscribers; // List of periods indexed by ID mapping (uint256 => Period) internal periods; event FeesPaid(address indexed subscriber, uint256 periods, uint256 newLastPeriodId, uint256 collectedFees, uint256 governorFee); event FeesDonated(address indexed payer, uint256 amount); event FeesClaimed(address indexed juror, uint256 indexed periodId, uint256 jurorShare); event GovernorFeesTransferred(uint256 amount); event FeeTokenChanged(address previousFeeToken, address currentFeeToken); event FeeAmountChanged(uint256 previousFeeAmount, uint256 currentFeeAmount); event PrePaymentPeriodsChanged(uint256 previousPrePaymentPeriods, uint256 currentPrePaymentPeriods); event GovernorSharePctChanged(uint16 previousGovernorSharePct, uint16 currentGovernorSharePct); event LatePaymentPenaltyPctChanged(uint16 previousLatePaymentPenaltyPct, uint16 currentLatePaymentPenaltyPct); event ResumePenaltiesChanged(uint256 previousResumePrePaidPeriods, uint256 currentResumePrePaidPeriods); /** * @dev Initialize court subscriptions * @param _controller Address of the controller * @param _periodDuration Duration of a subscription period in Court terms * @param _feeToken Initial ERC20 token used for the subscription fees * @param _feeAmount Initial amount of fees to be paid for each subscription period * @param _prePaymentPeriods Initial number of periods that can be paid in advance including the current period * @param _resumePrePaidPeriods Initial number of periods a subscriber must pre-pay in order to resume his activity after pausing * @param _latePaymentPenaltyPct Initial permyriad of subscription fees that will be applied as penalty for not paying during proper period (‱ - 1/10,000) * @param _governorSharePct Initial permyriad of subscription fees that will be allocated to the governor of the Court (‱ - 1/10,000) */ constructor( Controller _controller, uint64 _periodDuration, ERC20 _feeToken, uint256 _feeAmount, uint256 _prePaymentPeriods, uint256 _resumePrePaidPeriods, uint16 _latePaymentPenaltyPct, uint16 _governorSharePct ) ControlledRecoverable(_controller) public { // No need to explicitly call `Controlled` constructor since `ControlledRecoverable` is already doing it require(_periodDuration > 0, ERROR_PERIOD_DURATION_ZERO); periodDuration = _periodDuration; _setFeeToken(_feeToken); _setFeeAmount(_feeAmount); _setPrePaymentPeriods(_prePaymentPeriods); _setLatePaymentPenaltyPct(_latePaymentPenaltyPct); _setGovernorSharePct(_governorSharePct); _setResumePrePaidPeriods(_resumePrePaidPeriods); } /** * @notice Pay fees on behalf of `_to` for `_periods` periods * @param _to Subscriber whose subscription is being paid * @param _periods Number of periods to be paid in total since the last paid period */ function payFees(address _to, uint256 _periods) external { Subscriber storage subscriber = subscribers[_to]; require(!subscriber.paused, ERROR_SUBSCRIPTION_PAUSED); _payFees(subscriber, msg.sender, _to, _periods); // Initialize subscription for the requested subscriber if it is the first time paying fees if (!subscriber.subscribed) { subscriber.subscribed = true; } } /** * @notice Resume sender's subscription * @param _periods Number of periods to be paid in total */ function resume(uint256 _periods) external { Subscriber storage subscriber = subscribers[msg.sender]; require(subscriber.paused, ERROR_SUBSCRIPTION_NOT_PAUSED); _payFees(subscriber, msg.sender, msg.sender, _periods); subscriber.paused = false; subscriber.previousDelayedPeriods = 0; } /** * @notice Donate fees to the Court * @param _amount Amount of fee tokens to be donated */ function donate(uint256 _amount) external { require(_amount > 0, ERROR_DONATION_AMOUNT_ZERO); uint256 currentPeriodId = _getCurrentPeriodId(); Period storage period = periods[currentPeriodId]; (ERC20 feeToken, ) = _ensurePeriodFeeTokenAndAmount(period); period.collectedFees = period.collectedFees.add(_amount); // Deposit fee tokens from sender to this contract emit FeesDonated(msg.sender, _amount); require(feeToken.safeTransferFrom(msg.sender, address(this), _amount), ERROR_TOKEN_TRANSFER_FAILED); } /** * @notice Claim proportional share fees for period `_periodId` owed to `msg.sender` * @param _periodId Identification number of the period which fees are claimed for */ function claimFees(uint256 _periodId) external { // Juror share fees can only be claimed for past periods require(_periodId < _getCurrentPeriodId(), ERROR_NON_PAST_PERIOD); Period storage period = periods[_periodId]; require(!period.claimedFees[msg.sender], ERROR_JUROR_FEES_ALREADY_CLAIMED); // Check claiming juror has share fees to be transferred (uint64 periodBalanceCheckpoint, uint256 totalActiveBalance) = _ensurePeriodBalanceDetails(_periodId, period); uint256 jurorShare = _getJurorShare(msg.sender, period, periodBalanceCheckpoint, totalActiveBalance); require(jurorShare > 0, ERROR_JUROR_NOTHING_TO_CLAIM); // Update juror state and transfer share fees period.claimedFees[msg.sender] = true; emit FeesClaimed(msg.sender, _periodId, jurorShare); require(period.feeToken.safeTransfer(msg.sender, jurorShare), ERROR_TOKEN_TRANSFER_FAILED); } /** * @notice Pause sender subscriptions */ function pause() external { Subscriber storage subscriber = subscribers[msg.sender]; require(subscriber.subscribed, ERROR_SENDER_NOT_SUBSCRIBED); subscriber.previousDelayedPeriods = uint64(_getDelayedPeriods(subscriber, _getCurrentPeriodId())); subscriber.paused = true; } /** * @notice Transfer owed fees to the governor */ function transferFeesToGovernor() external { require(accumulatedGovernorFees > 0, ERROR_GOVERNOR_SHARE_FEES_ZERO); _transferFeesToGovernor(); } /** * @notice Make sure that the balance details of a certain period have been computed * @param _periodId Identification number of the period being ensured * @return periodBalanceCheckpoint Court term ID used to fetch the total active balance of the jurors registry * @return totalActiveBalance Total amount of juror tokens active in the Court at the corresponding used checkpoint */ function ensurePeriodBalanceDetails(uint256 _periodId) external returns (uint64 periodBalanceCheckpoint, uint256 totalActiveBalance) { Period storage period = periods[_periodId]; return _ensurePeriodBalanceDetails(_periodId, period); } /** * @notice Set new subscriptions fee amount to `_feeAmount` * @param _feeAmount New amount of fees to be paid for each subscription period */ function setFeeAmount(uint256 _feeAmount) external onlyConfigGovernor { _setFeeAmount(_feeAmount); } /** * @notice Set new subscriptions fee to `@tokenAmount(_feeToken, _feeAmount)` * @dev Accumulated fees owed to governor (if any) will be transferred * @param _feeToken New ERC20 token to be used for the subscription fees * @param _feeAmount New amount of fees to be paid for each subscription period */ function setFeeToken(ERC20 _feeToken, uint256 _feeAmount) external onlyConfigGovernor { // The `setFeeToken` function transfers governor's accumulated fees, so must be executed first. _setFeeToken(_feeToken); _setFeeAmount(_feeAmount); } /** * @notice Set new number of pre payment to `_prePaymentPeriods` periods * @param _prePaymentPeriods New number of periods that can be paid in advance */ function setPrePaymentPeriods(uint256 _prePaymentPeriods) external onlyConfigGovernor { _setPrePaymentPeriods(_prePaymentPeriods); } /** * @notice Set new late payment penalty `_latePaymentPenaltyPct`‱ (‱ - 1/10,000) * @param _latePaymentPenaltyPct New permyriad of subscription fees that will be applied as penalty for not paying during proper period */ function setLatePaymentPenaltyPct(uint16 _latePaymentPenaltyPct) external onlyConfigGovernor { _setLatePaymentPenaltyPct(_latePaymentPenaltyPct); } /** * @notice Set new governor share to `_governorSharePct`‱ (1/10,000) * @param _governorSharePct New permyriad of subscription fees that will be allocated to the governor of the Court (‱ - 1/10,000) */ function setGovernorSharePct(uint16 _governorSharePct) external onlyConfigGovernor { _setGovernorSharePct(_governorSharePct); } /** * @notice Set new resume pre-paid periods to `_resumePrePaidPeriods` * @param _resumePrePaidPeriods New number of periods a subscriber must pre-pay in order to resume his activity after pausing */ function setResumePrePaidPeriods(uint256 _resumePrePaidPeriods) external onlyConfigGovernor { _setResumePrePaidPeriods(_resumePrePaidPeriods); } /** * @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) { Subscriber storage subscriber = subscribers[_subscriber]; return subscriber.subscribed && !subscriber.paused && subscriber.lastPaymentPeriodId >= _getCurrentPeriodId(); } /** * @dev Tell the identification number of the current period * @return Identification number of the current period */ function getCurrentPeriodId() external view returns (uint256) { return _getCurrentPeriodId(); } /** * @dev Get details of the current period * @return feeToken Fee token corresponding to a certain subscription period * @return feeAmount Amount of fees paid for a certain subscription period * @return balanceCheckpoint Court term ID of a period used to fetch the total active balance of the jurors registry * @return totalActiveBalance Total amount of juror tokens active in the Court at the corresponding period checkpoint * @return collectedFees Total amount of subscription fees collected during a period */ function getCurrentPeriod() external view returns (ERC20 feeToken, uint256 feeAmount, uint64 balanceCheckpoint, uint256 totalActiveBalance, uint256 collectedFees) { uint256 currentPeriodId = _getCurrentPeriodId(); Period storage period = periods[currentPeriodId]; feeToken = period.feeToken; feeAmount = period.feeAmount; balanceCheckpoint = period.balanceCheckpoint; totalActiveBalance = period.totalActiveBalance; collectedFees = period.collectedFees; } /** * @dev Tell total active balance of the jurors registry at a random term during a certain period * @param _periodId Identification number of the period being queried * @return periodBalanceCheckpoint Court term ID used to fetch the total active balance of the jurors registry * @return totalActiveBalance Total amount of juror tokens active in the Court at the corresponding used checkpoint */ function getPeriodBalanceDetails(uint256 _periodId) external view returns (uint64 periodBalanceCheckpoint, uint256 totalActiveBalance) { return _getPeriodBalanceDetails(_periodId); } /** * @dev Tell information associated to a subscriber * @param _subscriber Address of the subscriber being queried * @return subscribed True if the given subscriber has already been subscribed to the Court, false otherwise * @return paused True if the given subscriber has paused the Court subscriptions, false otherwise * @return lastPaymentPeriodId Identification number of the last period paid by the given subscriber * @return previousDelayedPeriods Number of delayed periods the subscriber had before pausing */ function getSubscriber(address _subscriber) external view returns (bool subscribed, bool paused, uint64 lastPaymentPeriodId, uint64 previousDelayedPeriods) { Subscriber storage subscriber = subscribers[_subscriber]; subscribed = subscriber.subscribed; paused = subscriber.paused; lastPaymentPeriodId = subscriber.lastPaymentPeriodId; previousDelayedPeriods = subscriber.previousDelayedPeriods; } /** * @dev Tell the number of overdue payments for a given subscriber * @param _subscriber Address of the subscriber being checked * @return Number of overdue payments for the requested subscriber */ function getDelayedPeriods(address _subscriber) external view returns (uint256) { Subscriber storage subscriber = subscribers[_subscriber]; uint256 currentPeriodId = _getCurrentPeriodId(); return _getDelayedPeriods(subscriber, currentPeriodId); } /** * @dev Tell the amount to pay and resulting last paid period for a given subscriber paying for a certain number of periods * @param _subscriber Address of the subscriber being queried * @param _periods Number of periods that would be paid * @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 getPayFeesDetails(address _subscriber, uint256 _periods) external view returns (ERC20 feeToken, uint256 amountToPay, uint256 newLastPeriodId) { Subscriber storage subscriber = subscribers[_subscriber]; uint256 currentPeriodId = _getCurrentPeriodId(); uint256 feeAmount; (feeToken, feeAmount) = _getPeriodFeeTokenAndAmount(periods[currentPeriodId]); (amountToPay, newLastPeriodId) = _getPayFeesDetails(subscriber, _periods, currentPeriodId, feeAmount); } /** * @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 being queried * @return feeToken ERC20 token used for the subscription fees * @return amountToPay Amount of subscription fee tokens to be paid for all the owed periods * @return newLastPeriodId Identification number of the resulting last paid period */ function getOwedFeesDetails(address _subscriber) external view returns (ERC20 feeToken, uint256 amountToPay, uint256 newLastPeriodId) { Subscriber storage subscriber = subscribers[_subscriber]; uint256 currentPeriodId = _getCurrentPeriodId(); uint256 owedPeriods = _getOwedPeriods(subscriber, currentPeriodId); uint256 feeAmount; (feeToken, feeAmount) = _getPeriodFeeTokenAndAmount(periods[currentPeriodId]); if (owedPeriods == 0) { amountToPay = 0; newLastPeriodId = subscriber.lastPaymentPeriodId; } else { (amountToPay, newLastPeriodId) = _getPayFeesDetails(subscriber, owedPeriods, currentPeriodId, feeAmount); } } /** * @dev Tell the share fees corresponding to a juror for a certain period * @param _juror Address of the juror querying the owed shared fees of * @param _periodId Identification number of the period being queried * @return feeToken Address of the token used for the subscription fees * @return jurorShare Amount of share fees owed to the given juror for the requested period */ function getJurorShare(address _juror, uint256 _periodId) external view returns (ERC20 feeToken, uint256 jurorShare) { Period storage period = periods[_periodId]; uint64 periodBalanceCheckpoint; uint256 totalActiveBalance = period.totalActiveBalance; // Compute period balance details if they were not ensured yet if (totalActiveBalance == 0) { (periodBalanceCheckpoint, totalActiveBalance) = _getPeriodBalanceDetails(_periodId); } else { periodBalanceCheckpoint = period.balanceCheckpoint; } // Compute juror share fees using the period balance details jurorShare = _getJurorShare(_juror, period, periodBalanceCheckpoint, totalActiveBalance); (feeToken,) = _getPeriodFeeTokenAndAmount(period); } /** * @dev Check if a given juror has already claimed the owed share fees for a certain period * @param _juror Address of the juror being queried * @param _periodId Identification number of the period being queried * @return True if the owed share fees have already been claimed, false otherwise */ function hasJurorClaimed(address _juror, uint256 _periodId) external view returns (bool) { return periods[_periodId].claimedFees[_juror]; } /** * @dev Internal function to pay fees for a subscription * @param _subscriber Subscriber whose subscription is being paid * @param _from Address paying for the subscription fees * @param _to Address of the subscriber whose subscription is being paid * @param _periods Number of periods to be paid in total since the last paid period */ function _payFees(Subscriber storage _subscriber, address _from, address _to, uint256 _periods) internal { require(_periods > 0, ERROR_PAYING_ZERO_PERIODS); // Ensure fee token data for the current period uint256 currentPeriodId = _getCurrentPeriodId(); Period storage period = periods[currentPeriodId]; (ERC20 feeToken, uint256 feeAmount) = _ensurePeriodFeeTokenAndAmount(period); // Compute the total amount to pay by sender including the penalties for delayed periods (uint256 amountToPay, uint256 newLastPeriodId) = _getPayFeesDetails(_subscriber, _periods, currentPeriodId, feeAmount); // Compute the portion of the total amount to pay that will be allocated to the governor uint256 governorFee = amountToPay.pct(governorSharePct); accumulatedGovernorFees = accumulatedGovernorFees.add(governorFee); // Update collected fees for the jurors uint256 collectedFees = amountToPay.sub(governorFee); period.collectedFees = period.collectedFees.add(collectedFees); // Periods are measured in Court terms. Since Court terms are represented in uint64, we are safe to use uint64 for period ids too. _subscriber.lastPaymentPeriodId = uint64(newLastPeriodId); // Deposit fee tokens from sender to this contract emit FeesPaid(_to, _periods, newLastPeriodId, collectedFees, governorFee); require(feeToken.safeTransferFrom(_from, address(this), amountToPay), ERROR_TOKEN_TRANSFER_FAILED); } /** * @dev Internal function to transfer owed fees to the governor. This function assumes there are some accumulated fees to be transferred. */ function _transferFeesToGovernor() internal { uint256 amount = accumulatedGovernorFees; accumulatedGovernorFees = 0; emit GovernorFeesTransferred(amount); require(currentFeeToken.safeTransfer(_configGovernor(), amount), ERROR_TOKEN_TRANSFER_FAILED); } /** * @dev Internal function to make sure the fee token address and amount of a certain period have been cached * @param _period Period being ensured to have cached its fee token address and amount * @return feeToken ERC20 token to be used for the subscription fees during the given period * @return feeAmount Amount of fees to be paid during the given period */ function _ensurePeriodFeeTokenAndAmount(Period storage _period) internal returns (ERC20 feeToken, uint256 feeAmount) { // Use current fee token address and amount for the given period if these haven't been set yet feeToken = _period.feeToken; if (feeToken == ERC20(0)) { feeToken = currentFeeToken; _period.feeToken = feeToken; _period.feeAmount = currentFeeAmount; } feeAmount = _period.feeAmount; } /** * @dev Internal function to make sure that the balance details of a certain period have been computed. This function assumes given ID and * period correspond to each other. * @param _periodId Identification number of the period being ensured * @param _period Period being ensured * @return periodBalanceCheckpoint Court term ID used to fetch the total active balance of the jurors registry * @return totalActiveBalance Total amount of juror tokens active in the Court at the corresponding used checkpoint */ function _ensurePeriodBalanceDetails(uint256 _periodId, Period storage _period) internal returns (uint64 periodBalanceCheckpoint, uint256 totalActiveBalance) { totalActiveBalance = _period.totalActiveBalance; // Set balance details for the given period if these haven't been set yet if (totalActiveBalance == 0) { (periodBalanceCheckpoint, totalActiveBalance) = _getPeriodBalanceDetails(_periodId); _period.balanceCheckpoint = periodBalanceCheckpoint; _period.totalActiveBalance = totalActiveBalance; } else { periodBalanceCheckpoint = _period.balanceCheckpoint; } } /** * @dev Internal function to set a new amount for the subscription fees * @param _feeAmount New amount of fees to be paid for each subscription period */ function _setFeeAmount(uint256 _feeAmount) internal { require(_feeAmount > 0, ERROR_FEE_AMOUNT_ZERO); emit FeeAmountChanged(currentFeeAmount, _feeAmount); currentFeeAmount = _feeAmount; } /** * @dev Internal function to set a new ERC20 token for the subscription fees * @param _feeToken New ERC20 token to be used for the subscription fees */ function _setFeeToken(ERC20 _feeToken) internal { require(isContract(address(_feeToken)), ERROR_FEE_TOKEN_NOT_CONTRACT); if (accumulatedGovernorFees > 0) { _transferFeesToGovernor(); } emit FeeTokenChanged(address(currentFeeToken), address(_feeToken)); currentFeeToken = _feeToken; } /** * @dev Internal function to set a new number of pre payment periods * @param _prePaymentPeriods New number of periods that can be paid in advance including the current period */ function _setPrePaymentPeriods(uint256 _prePaymentPeriods) internal { // The pre payments period number must contemplate the current period. Thus, it must be greater than zero. require(_prePaymentPeriods > 0, ERROR_PREPAYMENT_PERIODS_ZERO); // It must be also greater than or equal to the number of resume pre-paid periods since these are always paid in advance, and we must // make sure there won't be users covering too many periods in the future to avoid skipping fee changes or excluding many jurors from // their corresponding rewards. require(_prePaymentPeriods >= resumePrePaidPeriods, ERROR_RESUME_PRE_PAID_PERIODS_TOO_BIG); emit PrePaymentPeriodsChanged(prePaymentPeriods, _prePaymentPeriods); prePaymentPeriods = _prePaymentPeriods; } /** * @dev Internal function to set new late payment penalty `_latePaymentPenaltyPct`‱ (1/10,000) * @param _latePaymentPenaltyPct New permyriad of subscription fees that will be applied as penalty for not paying during proper period */ function _setLatePaymentPenaltyPct(uint16 _latePaymentPenaltyPct) internal { emit LatePaymentPenaltyPctChanged(latePaymentPenaltyPct, _latePaymentPenaltyPct); latePaymentPenaltyPct = _latePaymentPenaltyPct; } /** * @dev Internal function to set a new governor share value * @param _governorSharePct New permyriad of subscription fees that will be allocated to the governor of the Court (‱ - 1/10,000) */ function _setGovernorSharePct(uint16 _governorSharePct) internal { // Check governor share is not greater than 10,000‱ require(PctHelpers.isValid(_governorSharePct), ERROR_OVERRATED_GOVERNOR_SHARE_PCT); emit GovernorSharePctChanged(governorSharePct, _governorSharePct); governorSharePct = _governorSharePct; } /** * @dev Internal function to set new number of resume pre-paid periods * @param _resumePrePaidPeriods New number of periods a subscriber must pre-pay in order to resume his activity after pausing */ function _setResumePrePaidPeriods(uint256 _resumePrePaidPeriods) internal { // Check resume resume pre-paid periods it not above the number of allowed pre payment periods. Since these periods are always paid in // advance, we must make sure there won't be users covering too many periods in the future to avoid skipping fee changes or // excluding many jurors from their corresponding rewards. require(_resumePrePaidPeriods <= prePaymentPeriods, ERROR_RESUME_PRE_PAID_PERIODS_TOO_BIG); emit ResumePenaltiesChanged(resumePrePaidPeriods, _resumePrePaidPeriods); resumePrePaidPeriods = _resumePrePaidPeriods; } /** * @dev Internal function to tell the identification number of the current period * @return Identification number of the current period */ function _getCurrentPeriodId() internal view returns (uint256) { // Since the Court starts at term #1, and the first subscription period is #0, then subtract one unit to the current term of the Court uint64 termId = _getCurrentTermId(); require(termId > 0, ERROR_COURT_HAS_NOT_STARTED); // No need for SafeMath: we already checked that the term ID is at least 1 uint64 periodId = (termId - START_TERM_ID) / periodDuration; return uint256(periodId); } /** * @dev Internal function to get the Court term in which a certain period starts * @param _periodId Identification number of the period querying the start term of * @return Court term where the given period starts */ function _getPeriodStartTermId(uint256 _periodId) internal view returns (uint64) { // Periods are measured in Court terms. Since Court terms are represented in uint64, we are safe to use uint64 for period ids too. // We are using SafeMath here because if any user calls `getPeriodBalanceDetails` for a huge period ID, // it would overflow and therefore return wrong information. return START_TERM_ID.add(uint64(_periodId).mul(periodDuration)); } /** * @dev Internal function to get the fee token address and amount to be used for a certain period * @param _period Period querying the token address and amount of * @return feeToken ERC20 token to be used for the subscription fees during the given period * @return feeAmount Amount of fees to be paid during the given period */ function _getPeriodFeeTokenAndAmount(Period storage _period) internal view returns (ERC20 feeToken, uint256 feeAmount) { // Return current fee token address and amount if these haven't been set for the given period yet feeToken = _period.feeToken; if (feeToken == ERC20(0)) { feeToken = currentFeeToken; feeAmount = currentFeeAmount; } else { feeAmount = _period.feeAmount; } } /** * @dev Internal function to compute the total amount of fees to be paid for the subscriber based on a requested number of periods * @param _subscriber Subscriber willing to pay * @param _periods Number of periods that would be paid * @param _currentPeriodId Identification number of the current period * @param _feeAmount Amount of fees to be paid for each subscription period * @return amountToPay Amount of subscription fee tokens to be paid * @return newLastPeriodId Identification number of the resulting last paid period */ function _getPayFeesDetails(Subscriber storage _subscriber, uint256 _periods, uint256 _currentPeriodId, uint256 _feeAmount) internal view returns (uint256 amountToPay, uint256 newLastPeriodId) { uint256 regularPeriods = 0; uint256 delayedPeriods = 0; uint256 resumePeriods = 0; (newLastPeriodId, regularPeriods, delayedPeriods, resumePeriods) = _getPayingPeriodsDetails(_subscriber, _periods, _currentPeriodId); // Regular periods to be paid is equal to `(regularPeriods + resumePeriods) * _feeAmount` uint256 regularPayment = (regularPeriods.add(resumePeriods)).mul(_feeAmount); // Delayed periods to be paid is equal to `delayedPeriods * _feeAmount * (1 + latePaymentPenaltyPct) / PCT_BASE` uint256 delayedPayment = delayedPeriods.mul(_feeAmount).pctIncrease(latePaymentPenaltyPct); // Compute total amount to be paid amountToPay = regularPayment.add(delayedPayment); } /** * @dev Internal function to compute the total number of different periods a subscriber has to pay based on a requested number of periods * * subs last paused current new last * +----+----+----+----+----+------+----+----+-------+----+----+----+--------+ * <---------> <-----------------><------------> * delayed regular resumed * * @param _subscriber Subscriber willing to pay * @param _periods Number of periods that would be paid * @param _currentPeriodId Identification number of the current period * @return newLastPeriodId Identification number of the resulting last paid period * @return regularPeriods Number of periods to be paid without penalties * @return delayedPeriods Number of periods to be paid applying the delayed penalty * @return resumePeriods Number of periods to be paid applying the resume penalty */ function _getPayingPeriodsDetails(Subscriber storage _subscriber, uint256 _periods, uint256 _currentPeriodId) internal view returns (uint256 newLastPeriodId, uint256 regularPeriods, uint256 delayedPeriods, uint256 resumePeriods) { uint256 lastPaymentPeriodId = _subscriber.lastPaymentPeriodId; // Check if the subscriber has already been subscribed if (!_subscriber.subscribed) { // If the subscriber was not subscribed before, there are no delayed nor resumed periods resumePeriods = 0; delayedPeriods = 0; regularPeriods = _periods; // The number of periods to be paid includes the current period, thus we subtract one unit // No need for SafeMath: the number of periods is at least one newLastPeriodId = _currentPeriodId.add(_periods) - 1; } else { uint256 totalDelayedPeriods = _getDelayedPeriods(_subscriber, _currentPeriodId); // Resume a subscription only if the subscriber was paused and the previous last period is overdue by more than one period if (_subscriber.paused && lastPaymentPeriodId + 1 < _currentPeriodId) { // If the subscriber is resuming his activity he must pay the pre-paid periods penalty and the previous delayed periods resumePeriods = resumePrePaidPeriods; delayedPeriods = totalDelayedPeriods; require(_periods >= resumePeriods.add(delayedPeriods), ERROR_LOW_RESUME_PERIODS_PAYMENT); // No need for SafeMath: we already checked the number of given and resume periods above regularPeriods = _periods - resumePeriods - delayedPeriods; // The new last period is computed including the current period // No need for SafeMath: the number of periods is at least one newLastPeriodId = _currentPeriodId.add(_periods) - 1; } else { // If the subscriber does not need to resume his activity, there are no resume periods, last period is simply updated resumePeriods = 0; newLastPeriodId = lastPaymentPeriodId.add(_periods); // Compute the number of regular and delayed periods to be paid if (totalDelayedPeriods > _periods) { // Non regular periods, all periods being paid are delayed ones regularPeriods = 0; delayedPeriods = _periods; } else { // No need for SafeMath: we already checked the total number of delayed periods regularPeriods = _periods - totalDelayedPeriods; delayedPeriods = totalDelayedPeriods; } } } // If the subscriber is paying some periods in advance, check it doesn't reach the pre-payment limit if (newLastPeriodId > _currentPeriodId) { require(newLastPeriodId.sub(_currentPeriodId) < prePaymentPeriods, ERROR_PAYING_TOO_MANY_PERIODS); } } /** * @dev Internal function to tell the number of overdue payments for a given subscriber * @param _subscriber Subscriber querying the delayed periods of * @param _currentPeriodId Identification number of the current period * @return Number of overdue payments for the requested subscriber */ function _getDelayedPeriods(Subscriber storage _subscriber, uint256 _currentPeriodId) internal view returns (uint256) { // If the given subscriber was not subscribed yet, there are no pending payments if (!_subscriber.subscribed) { return 0; } // If the given subscriber was paused, return the delayed periods before pausing if (_subscriber.paused) { return _subscriber.previousDelayedPeriods; } // If the given subscriber is subscribed and not paused but is up-to-date, return 0 uint256 lastPaymentPeriodId = _subscriber.lastPaymentPeriodId; if (lastPaymentPeriodId >= _currentPeriodId) { return 0; } // If the given subscriber was already subscribed, then the current period is not considered delayed // No need for SafeMath: we already know last payment period is before current period from above return _currentPeriodId - lastPaymentPeriodId - 1; } /** * @dev Internal function to tell the number of owed payments for a given subscriber * @param _subscriber Subscriber querying the delayed periods of * @param _currentPeriodId Identification number of the current period * @return Number of owed payments for the requested subscriber */ function _getOwedPeriods(Subscriber storage _subscriber, uint256 _currentPeriodId) internal view returns (uint256) { // If the given subscriber was not subscribed yet, they must only pay the current period if (!_subscriber.subscribed) { return 1; } uint256 lastPaymentPeriodId = _subscriber.lastPaymentPeriodId; uint256 totalDelayedPeriods = _getDelayedPeriods(_subscriber, _currentPeriodId); // If the subscriber was paused and the previous last period is overdue by more than one period, // the subscriber must pay the pre-paid resume penalty and their previous delayed periods if (_subscriber.paused && lastPaymentPeriodId + 1 < _currentPeriodId) { return resumePrePaidPeriods.add(totalDelayedPeriods); } // If the subscriber is not paused or the last period is not overdue by more than one period, // check if they have paid in advance some periods if (lastPaymentPeriodId >= _currentPeriodId) { return 0; } // Otherwise, they simply need to pay the number of delayed periods and the current period return totalDelayedPeriods + 1; } /** * @dev Internal function to get the total active balance of the jurors registry at a random term during a period * @param _periodId Identification number of the period being queried * @return periodBalanceCheckpoint Court term ID used to fetch the total active balance of the jurors registry * @return totalActiveBalance Total amount of juror tokens active in the Court at the corresponding used checkpoint */ function _getPeriodBalanceDetails(uint256 _periodId) internal view returns (uint64 periodBalanceCheckpoint, uint256 totalActiveBalance) { uint64 periodStartTermId = _getPeriodStartTermId(_periodId); uint64 nextPeriodStartTermId = _getPeriodStartTermId(_periodId.add(1)); // Pick a random Court term during the next period of the requested one to get the total amount of juror tokens active in the Court IClock clock = _clock(); bytes32 randomness = clock.getTermRandomness(nextPeriodStartTermId); // The randomness factor for each Court term is computed using the the hash of a block number set during the initialization of the // term, to ensure it cannot be known beforehand. Note that the hash function being used only works for the 256 most recent block // numbers. Therefore, if that occurs we use the hash of the previous block number. This could be slightly beneficial for the first // juror calling this function, but it's still impossible to predict during the requested period. if (randomness == bytes32(0)) { randomness = blockhash(getBlockNumber() - 1); } // Use randomness to choose a Court term of the requested period and query the total amount of juror tokens active at that term IJurorsRegistry jurorsRegistry = _jurorsRegistry(); periodBalanceCheckpoint = periodStartTermId.add(uint64(uint256(randomness) % periodDuration)); totalActiveBalance = jurorsRegistry.totalActiveBalanceAt(periodBalanceCheckpoint); } /** * @dev Internal function to tell the share fees corresponding to a juror for a certain period * @param _juror Address of the juror querying the owed shared fees of * @param _period Period being queried * @param _periodBalanceCheckpoint Court term ID used to fetch the active balance of the juror for the requested period * @param _totalActiveBalance Total amount of juror tokens active in the Court at the corresponding used checkpoint * @return Amount of share fees owed to the given juror for the requested period */ function _getJurorShare(address _juror, Period storage _period, uint64 _periodBalanceCheckpoint, uint256 _totalActiveBalance) internal view returns (uint256) { // Fetch juror active balance at the checkpoint used for the requested period IJurorsRegistry jurorsRegistry = _jurorsRegistry(); uint256 jurorActiveBalance = jurorsRegistry.activeBalanceOfAt(_juror, _periodBalanceCheckpoint); if (jurorActiveBalance == 0) { return 0; } // Note that we already checked the juror active balance is greater than zero, then, the total active balance must be greater than zero. return _period.collectedFees.mul(jurorActiveBalance) / _totalActiveBalance; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[],"name":"getCurrentPeriod","outputs":[{"name":"feeToken","type":"address"},{"name":"feeAmount","type":"uint256"},{"name":"balanceCheckpoint","type":"uint64"},{"name":"totalActiveBalance","type":"uint256"},{"name":"collectedFees","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_subscriber","type":"address"}],"name":"getOwedFeesDetails","outputs":[{"name":"feeToken","type":"address"},{"name":"amountToPay","type":"uint256"},{"name":"newLastPeriodId","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_to","type":"address"}],"name":"recoverFunds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_governorSharePct","type":"uint16"}],"name":"setGovernorSharePct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentFeeAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"resumePrePaidPeriods","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getController","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"prePaymentPeriods","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentPeriodId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_periods","type":"uint256"}],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"latePaymentPenaltyPct","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_subscriber","type":"address"}],"name":"getSubscriber","outputs":[{"name":"subscribed","type":"bool"},{"name":"paused","type":"bool"},{"name":"lastPaymentPeriodId","type":"uint64"},{"name":"previousDelayedPeriods","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_latePaymentPenaltyPct","type":"uint16"}],"name":"setLatePaymentPenaltyPct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_feeAmount","type":"uint256"}],"name":"setFeeAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_periodId","type":"uint256"}],"name":"getPeriodBalanceDetails","outputs":[{"name":"periodBalanceCheckpoint","type":"uint64"},{"name":"totalActiveBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"accumulatedGovernorFees","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_subscriber","type":"address"}],"name":"getDelayedPeriods","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_subscriber","type":"address"},{"name":"_periods","type":"uint256"}],"name":"getPayFeesDetails","outputs":[{"name":"feeToken","type":"address"},{"name":"amountToPay","type":"uint256"},{"name":"newLastPeriodId","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_periodId","type":"uint256"}],"name":"claimFees","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentFeeToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"periodDuration","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_feeToken","type":"address"},{"name":"_feeAmount","type":"uint256"}],"name":"setFeeToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"transferFeesToGovernor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_periods","type":"uint256"}],"name":"payFees","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_prePaymentPeriods","type":"uint256"}],"name":"setPrePaymentPeriods","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_juror","type":"address"},{"name":"_periodId","type":"uint256"}],"name":"hasJurorClaimed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_juror","type":"address"},{"name":"_periodId","type":"uint256"}],"name":"getJurorShare","outputs":[{"name":"feeToken","type":"address"},{"name":"jurorShare","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_resumePrePaidPeriods","type":"uint256"}],"name":"setResumePrePaidPeriods","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"donate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"governorSharePct","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_periodId","type":"uint256"}],"name":"ensurePeriodBalanceDetails","outputs":[{"name":"periodBalanceCheckpoint","type":"uint64"},{"name":"totalActiveBalance","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_subscriber","type":"address"}],"name":"isUpToDate","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_controller","type":"address"},{"name":"_periodDuration","type":"uint64"},{"name":"_feeToken","type":"address"},{"name":"_feeAmount","type":"uint256"},{"name":"_prePaymentPeriods","type":"uint256"},{"name":"_resumePrePaidPeriods","type":"uint256"},{"name":"_latePaymentPenaltyPct","type":"uint16"},{"name":"_governorSharePct","type":"uint16"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"subscriber","type":"address"},{"indexed":false,"name":"periods","type":"uint256"},{"indexed":false,"name":"newLastPeriodId","type":"uint256"},{"indexed":false,"name":"collectedFees","type":"uint256"},{"indexed":false,"name":"governorFee","type":"uint256"}],"name":"FeesPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"payer","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"FeesDonated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"juror","type":"address"},{"indexed":true,"name":"periodId","type":"uint256"},{"indexed":false,"name":"jurorShare","type":"uint256"}],"name":"FeesClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"GovernorFeesTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"previousFeeToken","type":"address"},{"indexed":false,"name":"currentFeeToken","type":"address"}],"name":"FeeTokenChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"previousFeeAmount","type":"uint256"},{"indexed":false,"name":"currentFeeAmount","type":"uint256"}],"name":"FeeAmountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"previousPrePaymentPeriods","type":"uint256"},{"indexed":false,"name":"currentPrePaymentPeriods","type":"uint256"}],"name":"PrePaymentPeriodsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"previousGovernorSharePct","type":"uint16"},{"indexed":false,"name":"currentGovernorSharePct","type":"uint16"}],"name":"GovernorSharePctChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"previousLatePaymentPenaltyPct","type":"uint16"},{"indexed":false,"name":"currentLatePaymentPenaltyPct","type":"uint16"}],"name":"LatePaymentPenaltyPctChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"previousResumePrePaidPeriods","type":"uint256"},{"indexed":false,"name":"currentResumePrePaidPeriods","type":"uint256"}],"name":"ResumePenaltiesChanged","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
60806040523480156200001157600080fd5b506040516101008062003e5083398101806040526101008110156200003557600080fd5b50805160208083015160408401516060850151608086015160a087015160c088015160e090980151969794969395929491939092889081906200007e908290620002ce811b901c565b6040518060400160405280601b81526020017f4354445f434f4e54524f4c4c45525f4e4f545f434f4e54524143540000000000815250906200015b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156200011f57818101518382015260200162000105565b50505050905090810190601f1680156200014d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600080546001600160a01b0319166001600160a01b03929092169190911790555060408051808201909152601781527f43535f504552494f445f4455524154494f4e5f5a45524f00000000000000000060208201526001600160401b03881662000223576040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482018181528351602484015283519092839260449091019190850190808383600083156200011f57818101518382015260200162000105565b5060008054600160a01b600160e01b031916740100000000000000000000000000000000000000006001600160401b038a16021790556200026b86620002f3602090811b901c565b6200027c856200042760201b60201c565b6200028d846200050760201b60201c565b6200029e826200068d60201b60201c565b620002af816200072e60201b60201c565b620002c0836200088760201b60201c565b505050505050505062000be5565b60006001600160a01b038216620002e857506000620002ee565b50803b15155b919050565b6200030481620002ce60201b60201c565b6040518060400160405280601981526020017f43535f4645455f544f4b454e5f4e4f545f434f4e54524143540000000000000081525090620003a3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482018181528351602484015283519092839260449091019190850190808383600083156200011f57818101518382015260200162000105565b5060055415620003bd57620003bd6200096f60201b60201c565b600154604080516001600160a01b039283168152918316602083015280517f1080b8de45190ac9d8745f3724225c9b50b849890e73595c4403edd52b9493709281900390910190a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b60408051808201909152601281527f43535f4645455f414d4f554e545f5a45524f0000000000000000000000000000602082015281620004c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482018181528351602484015283519092839260449091019190850190808383600083156200011f57818101518382015260200162000105565b50600254604080519182526020820183905280517f628999ddb8cc6bb99cec0350ca6e43277be4a15b13e849d3e532cada20effa829281900390910190a1600255565b60408051808201909152601a81527f43535f5052455041594d454e545f504552494f44535f5a45524f000000000000602082015281620005a4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482018181528351602484015283519092839260449091019190850190808383600083156200011f57818101518382015260200162000105565b506004548110156040518060400160405280601e81526020017f43535f524553554d455f5052455f504149445f504552494f44535f4249470000815250906200064a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482018181528351602484015283519092839260449091019190850190808383600083156200011f57818101518382015260200162000105565b50600354604080519182526020820183905280517f4250689f302002c7a5d16d204db28ba5f50190081ed4fa93e6254c1db1ebe1419281900390910190a1600355565b6000546040805161ffff7c010000000000000000000000000000000000000000000000000000000090930483168152918316602083015280517f95b30c5823523338cceacb3f088dd8ddba9e49ecf086cd8311cc9f2a51755e5f9281900390910190a16000805461ffff9092167c010000000000000000000000000000000000000000000000000000000002600160e01b61ffff0219909216919091179055565b620007448162000a8260201b62002f7c1760201c565b6040518060400160405280601f81526020017f43535f4f56455252415445445f474f5645524e4f525f53484152455f5043540081525090620007e3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482018181528351602484015283519092839260449091019190850190808383600083156200011f57818101518382015260200162000105565b506000546040805161ffff7e0100000000000000000000000000000000000000000000000000000000000090930483168152918316602083015280517f16b68bb17a802748657198a6c1752356706af9761fed9a0aec01e18dbab22e3d9281900390910190a16000805461ffff9092167e01000000000000000000000000000000000000000000000000000000000000026001600160f01b03909216919091179055565b6003548111156040518060400160405280601e81526020017f43535f524553554d455f5052455f504149445f504552494f44535f4249470000815250906200092c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482018181528351602484015283519092839260449091019190850190808383600083156200011f57818101518382015260200162000105565b50600454604080519182526020820183905280517fec8da95e790f837a162434052aacad1a02c3ac922306093a55b37d08bc189d1d9281900390910190a1600455565b6005805460009091556040805182815290517f8d4b456a5bf2af7af0c51b59d87fd03dec21a0d682d194c3181d3597962d2a6d9181900360200190a1620009df620009bf62000a9160201b60201c565b6001546001600160a01b0316908362000b14602090811b62001c4e17901c565b6040518060400160405280601881526020017f43535f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509062000a7e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482018181528351602484015283519092839260449091019190850190808383600083156200011f57818101518382015260200162000105565b5050565b61271061ffff82161115919050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166397023f816040518163ffffffff1660e01b815260040160206040518083038186803b15801562000ae157600080fd5b505afa15801562000af6573d6000803e3d6000fd5b505050506040513d602081101562000b0d57600080fd5b5051905090565b604080516001600160a01b03841660248201526044808201849052825180830390910181526064909101909152602081810180516001600160e01b03167fa9059cbb000000000000000000000000000000000000000000000000000000001790526000919062000b8c908690839062000b95811b901c565b95945050505050565b6000806040516020818551602087016000895af1801562000bdb573d801562000bc7576020811462000bd15762000bd9565b6001935062000bd9565b600183511493505b505b5090949350505050565b61325b8062000bf56000396000f3fe608060405234801561001057600080fd5b506004361061020b5760003560e01c8063831918821161012a578063de974ba4116100bd578063f06392671161008c578063fcdecfd011610071578063fcdecfd014610650578063fd13b07d14610658578063fd8e3934146106755761020b565b8063f063926714610616578063f14faf6f146106335761020b565b8063de974ba41461053e578063ded774291461056a578063e786a53914610587578063e8f45561146105c75761020b565b8063b2eed6dd116100f9578063b2eed6dd146104dd578063b470aade146104e5578063bf416be61461050a578063d49e3c88146105365761020b565b806383191882146104665780638456cb591461048c5780638f904a2114610494578063ac68a748146104c05761020b565b8063396b6247116101a2578063689e770011610171578063689e7700146103df5780636b392680146104005780637b8bc6451461041d578063830257371461045e5761020b565b8063396b624714610343578063414000b51461034b5780635a7dca57146103685780635abf3838146103875761020b565b80632d725d06116101de5780632d725d06146102f55780632db9d4f41461030f5780633018205f1461031757806338ca029a1461033b5761020b565b8063086146d2146102105780630a771c251461025657806324ae6a27146102a457806329577d51146102d4575b600080fd5b61021861069b565b604080516001600160a01b039096168652602086019490945267ffffffffffffffff9092168484015260608401526080830152519081900360a00190f35b61027c6004803603602081101561026c57600080fd5b50356001600160a01b03166106fd565b604080516001600160a01b039094168452602084019290925282820152519081900360600190f35b6102d2600480360360408110156102ba57600080fd5b506001600160a01b038135811691602001351661078f565b005b6102d2600480360360208110156102ea57600080fd5b503561ffff16610ad9565b6102fd610b87565b60408051918252519081900360200190f35b6102fd610b8d565b61031f610b93565b604080516001600160a01b039092168252519081900360200190f35b6102fd610ba2565b6102fd610ba8565b6102d26004803603602081101561036157600080fd5b5035610bb7565b610370610c8e565b6040805161ffff9092168252519081900360200190f35b6103ad6004803603602081101561039d57600080fd5b50356001600160a01b0316610cb8565b604080519415158552921515602085015267ffffffffffffffff91821684840152166060830152519081900360800190f35b6102d2600480360360208110156103f557600080fd5b503561ffff16610d04565b6102d26004803603602081101561041657600080fd5b5035610daf565b61043a6004803603602081101561043357600080fd5b5035610e5a565b6040805167ffffffffffffffff909316835260208301919091528051918290030190f35b6102fd610e70565b6102fd6004803603602081101561047c57600080fd5b50356001600160a01b0316610e76565b6102d2610ead565b61027c600480360360408110156104aa57600080fd5b506001600160a01b038135169060200135610fc6565b6102d2600480360360208110156104d657600080fd5b5035611026565b61031f611328565b6104ed611337565b6040805167ffffffffffffffff9092168252519081900360200190f35b6102d26004803603604081101561052057600080fd5b506001600160a01b03813516906020013561135f565b6102d2611417565b6102d26004803603604081101561055457600080fd5b506001600160a01b0381351690602001356114ad565b6102d26004803603602081101561058057600080fd5b503561159d565b6105b36004803603604081101561059d57600080fd5b506001600160a01b038135169060200135611648565b604080519115158252519081900360200190f35b6105f3600480360360408110156105dd57600080fd5b506001600160a01b038135169060200135611678565b604080516001600160a01b03909316835260208301919091528051918290030190f35b6102d26004803603602081101561062c57600080fd5b50356116dc565b6102d26004803603602081101561064957600080fd5b5035611787565b61037061192a565b61043a6004803603602081101561066e57600080fd5b5035611956565b6105b36004803603602081101561068b57600080fd5b50356001600160a01b031661197a565b6000806000806000806106ac6119d5565b60009081526007602052604090208054600182015460028301546003909301546001600160a01b03680100000000000000008404169a91995067ffffffffffffffff90921697509195509350915050565b6001600160a01b038116600090815260066020526040812081908190816107226119d5565b905060006107308383611adc565b60008381526007602052604081209192509061074b90611b67565b9097509050816107725783546000965062010000900467ffffffffffffffff169450610784565b61077e84838584611ba9565b90965094505b505050509193909250565b6000809054906101000a90046001600160a01b03166001600160a01b0316633c28e88b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156107dc57600080fd5b505afa1580156107f0573d6000803e3d6000fd5b505050506040513d602081101561080657600080fd5b505160408051808201909152601d81527f4354445f53454e4445525f4e4f545f46554e44535f474f5645524e4f520000006020820152906001600160a01b031633146108d357604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610898578181015183820152602001610880565b50505050905090810190601f1680156108c55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290516000916001600160a01b038516916370a0823191602480820192602092909190829003018186803b15801561093757600080fd5b505afa15801561094b573d6000803e3d6000fd5b505050506040513d602081101561096157600080fd5b505160408051808201909152601e81527f4354445f494e53554646494349454e545f5245434f5645525f46554e445300006020820152909150816109e957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610a046001600160a01b038416838363ffffffff611c4e16565b6040518060400160405280601e81526020017f4354445f5245434f5645525f544f4b454e5f46554e44535f4641494c4544000081525090610a8957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50604080516001600160a01b0380861682528416602082015280820183905290517f724139fea3954691c2c1ee02b3be6be1763b32ec84841f1acad6d3a18695ba0d9181900360600190a1505050565b610ae1611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f52000081525090610b7a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610b8481611d59565b50565b60025481565b60045481565b6000546001600160a01b031690565b60035481565b6000610bb26119d5565b905090565b3360009081526006602090815260409182902080548351808501909452601a84527f43535f535542534352495054494f4e5f4e4f545f504155534544000000000000928401929092529190610100900460ff16610c5857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610c6581333385611ea2565b80547fffffffffffffffffffffffffffff0000000000000000ffffffffffffffff00ff16905550565b6000547c0100000000000000000000000000000000000000000000000000000000900461ffff1681565b6001600160a01b031660009081526006602052604090205460ff8082169261010083049091169167ffffffffffffffff6201000082048116926a01000000000000000000009092041690565b610d0c611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f52000081525090610da557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610b848161211d565b610db7611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f52000081525090610e5057604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610b84816121d5565b600080610e668361229b565b915091505b915091565b60055481565b6001600160a01b038116600090815260066020526040812081610e976119d5565b9050610ea3828261245a565b925050505b919050565b3360009081526006602090815260409182902080548351808501909452601884527f43535f53454e4445525f4e4f545f53554253435249424544000000000000000092840192909252919060ff16610f4957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610f5b81610f566119d5565b61245a565b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff67ffffffffffffffff929092166a0100000000000000000000027fffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffff9091161716610100179055565b6001600160a01b03821660009081526006602052604081208190819081610feb6119d5565b60008181526007602052604081209192509061100690611b67565b909650905061101783888484611ba9565b96999098509596505050505050565b61102e6119d5565b81106040518060400160405280601281526020017f43535f4e4f4e5f504153545f504552494f440000000000000000000000000000815250906110b557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50600081815260076020908152604080832033845260048101835292819020548151808301909252601d82527f43535f4a55524f525f464545535f414c52454144595f434c41494d4544000000928201929092529060ff161561115c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5060008061116a84846124eb565b91509150600061117c3385858561255a565b9050600081116040518060400160405280601981526020017f43535f4a55524f525f4e4f5448494e475f544f5f434c41494d000000000000008152509061120757604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5033600081815260048601602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055815184815291518893927f1ac537f0ad67b64ac68a04587ff3a4cb6977de22eb2c37ee560897a92c6d07c792908290030190a3835461129b906801000000000000000090046001600160a01b03163383611c4e565b6040518060400160405280601881526020017f43535f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509061132057604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b505050505050565b6001546001600160a01b031681565b60005474010000000000000000000000000000000000000000900467ffffffffffffffff1681565b611367611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f5200008152509061140057604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5061140a82612648565b611413816121d5565b5050565b6000600554116040518060400160405280601b81526020017f43535f474f5645524e4f525f53484152455f464545535f5a45524f0000000000815250906114a257604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b506114ab612769565b565b6001600160a01b03821660009081526006602090815260409182902080548351808501909452601684527f43535f535542534352495054494f4e5f50415553454400000000000000000000928401929092529190610100900460ff161561155857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5061156581338585611ea2565b805460ff166115985780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781555b505050565b6115a5611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f5200008152509061163e57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610b848161284e565b60008181526007602090815260408083206001600160a01b038616845260040190915290205460ff165b92915050565b600081815260076020526040812060028101548291908290806116a85761169e8661229b565b90925090506116b7565b825467ffffffffffffffff1691505b6116c38784848461255a565b93506116ce83611b67565b509793965092945050505050565b6116e4611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f5200008152509061177d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610b84816129a0565b60408051808201909152601781527f43535f444f4e4154494f4e5f414d4f554e545f5a45524f00000000000000000060208201528161180a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5060006118156119d5565b600081815260076020526040812091925061182f82612a6e565b506003830154909150611848908563ffffffff612ae016565b600383015560408051858152905133917f27ef414ce6fa80a9350ddb76cf40cdd3f926f1d61450480b3cd52e7c889a1f93919081900360200190a261189e6001600160a01b03821633308763ffffffff612b7516565b6040518060400160405280601881526020017f43535f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509061192357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5050505050565b6000547e01000000000000000000000000000000000000000000000000000000000000900461ffff1681565b6000818152600760205260408120819061197084826124eb565b9250925050915091565b6001600160a01b0381166000908152600660205260408120805460ff1680156119aa57508054610100900460ff16155b80156119ce57506119b96119d5565b815462010000900467ffffffffffffffff1610155b9392505050565b6000806119e0612c09565b905060008167ffffffffffffffff16116040518060400160405280601881526020017f43535f434f5552545f4841535f4e4f545f53544152544544000000000000000081525090611a7557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b506000805467ffffffffffffffff740100000000000000000000000000000000000000009091048116907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84011681611aca57fe5b0467ffffffffffffffff169392505050565b815460009060ff16611af057506001611672565b825462010000900467ffffffffffffffff166000611b0e858561245a565b8554909150610100900460ff168015611b2957508382600101105b15611b4a57600454611b41908263ffffffff612ae016565b92505050611672565b838210611b5c57600092505050611672565b600101949350505050565b80546801000000000000000090046001600160a01b0316600081611b9e5750506001546002546001600160a01b0390911690610e6b565b506001820154915091565b600080808080611bba898989612c4b565b929650909450925090506000611be687611bda868563ffffffff612ae016565b9063ffffffff612e6416565b6000805491925090611c2c907c0100000000000000000000000000000000000000000000000000000000900461ffff16611c20868b612e64565b9063ffffffff612f0716565b9050611c3e828263ffffffff612ae016565b9650505050505094509492505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600090611cd08582612f31565b95945050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166397023f816040518163ffffffff1660e01b815260040160206040518083038186803b158015611d2857600080fd5b505afa158015611d3c573d6000803e3d6000fd5b505050506040513d6020811015611d5257600080fd5b5051905090565b611d6281612f7c565b6040518060400160405280601f81526020017f43535f4f56455252415445445f474f5645524e4f525f53484152455f5043540081525090611de757604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b506000546040805161ffff7e0100000000000000000000000000000000000000000000000000000000000090930483168152918316602083015280517f16b68bb17a802748657198a6c1752356706af9761fed9a0aec01e18dbab22e3d9281900390910190a16000805461ffff9092167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60408051808201909152601681527f43535f504159494e475f5a45524f5f504552494f445300000000000000000000602082015281611f2557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b506000611f306119d5565b600081815260076020526040812091925080611f4b83612a6e565b91509150600080611f5e8a888886611ba9565b6000805492945090925090611f9a9084907e01000000000000000000000000000000000000000000000000000000000000900461ffff16612f8b565b600554909150611fb0908263ffffffff612ae016565b6005556000611fc5848363ffffffff612fa416565b6003880154909150611fdd908263ffffffff612ae016565b60038801558b5467ffffffffffffffff841662010000027fffffffffffffffffffffffffffffffffffffffffffff0000000000000000ffff909116178c55604080518a8152602081018590528082018390526060810184905290516001600160a01b038c16917f490965cdfe01182ccdb9781fc760b4655fbf35e70e531d1572fd0bb96adb92b7919081900360800190a26120896001600160a01b0387168c308763ffffffff612b7516565b6040518060400160405280601881526020017f43535f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509061210e57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50505050505050505050505050565b6000546040805161ffff7c010000000000000000000000000000000000000000000000000000000090930483168152918316602083015280517f95b30c5823523338cceacb3f088dd8ddba9e49ecf086cd8311cc9f2a51755e5f9281900390910190a16000805461ffff9092167c0100000000000000000000000000000000000000000000000000000000027fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60408051808201909152601281527f43535f4645455f414d4f554e545f5a45524f000000000000000000000000000060208201528161225857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50600254604080519182526020820183905280517f628999ddb8cc6bb99cec0350ca6e43277be4a15b13e849d3e532cada20effa829281900390910190a1600255565b60008060006122a984613036565b905060006122c66122c186600163ffffffff612ae016565b613036565b905060006122d2610b93565b90506000816001600160a01b03166361f3be6a846040518263ffffffff1660e01b8152600401808267ffffffffffffffff1667ffffffffffffffff16815260200191505060206040518083038186803b15801561232e57600080fd5b505afa158015612342573d6000803e3d6000fd5b505050506040513d602081101561235857600080fd5b505190508061237057600161236b613081565b034090505b600061237a613085565b6000549091506123c79074010000000000000000000000000000000000000000900467ffffffffffffffff1683816123ae57fe5b67ffffffffffffffff881691900663ffffffff6130d416565b9650806001600160a01b0316638e127793886040518263ffffffff1660e01b8152600401808267ffffffffffffffff1667ffffffffffffffff16815260200191505060206040518083038186803b15801561242157600080fd5b505afa158015612435573d6000803e3d6000fd5b505050506040513d602081101561244b57600080fd5b50519698969750505050505050565b815460009060ff1661246e57506000611672565b8254610100900460ff161561249d575081546a0100000000000000000000900467ffffffffffffffff16611672565b825462010000900467ffffffffffffffff168281106124c0576000915050611672565b9091037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b600281015460009080612544576125018461229b565b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff8316178555600285018190559092509050612553565b825467ffffffffffffffff1691505b9250929050565b600080612565613085565b604080517fe9e67d670000000000000000000000000000000000000000000000000000000081526001600160a01b03898116600483015267ffffffffffffffff8816602483015291519293506000929184169163e9e67d6791604480820192602092909190829003018186803b1580156125de57600080fd5b505afa1580156125f2573d6000803e3d6000fd5b505050506040513d602081101561260857600080fd5b505190508061261c57600092505050612640565b60038601548490612633908363ffffffff612e6416565b8161263a57fe5b04925050505b949350505050565b6126518161316e565b6040518060400160405280601981526020017f43535f4645455f544f4b454e5f4e4f545f434f4e545241435400000000000000815250906126d657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50600554156126e7576126e7612769565b600154604080516001600160a01b039283168152918316602083015280517f1080b8de45190ac9d8745f3724225c9b50b849890e73595c4403edd52b9493709281900390910190a1600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6005805460009091556040805182815290517f8d4b456a5bf2af7af0c51b59d87fd03dec21a0d682d194c3181d3597962d2a6d9181900360200190a16127c96127b0611cd9565b6001546001600160a01b0316908363ffffffff611c4e16565b6040518060400160405280601881526020017f43535f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509061141357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b60408051808201909152601a81527f43535f5052455041594d454e545f504552494f44535f5a45524f0000000000006020820152816128d157604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b506004548110156040518060400160405280601e81526020017f43535f524553554d455f5052455f504149445f504552494f44535f42494700008152509061295d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50600354604080519182526020820183905280517f4250689f302002c7a5d16d204db28ba5f50190081ed4fa93e6254c1db1ebe1419281900390910190a1600355565b6003548111156040518060400160405280601e81526020017f43535f524553554d455f5052455f504149445f504552494f44535f424947000081525090612a2b57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50600454604080519182526020820183905280517fec8da95e790f837a162434052aacad1a02c3ac922306093a55b37d08bc189d1d9281900390910190a1600455565b80546801000000000000000090046001600160a01b0316600081611b9e5750506001805482547fffffffff0000000000000000000000000000000000000000ffffffffffffffff166001600160a01b039091166801000000000000000081029190911783556002549290910182905591565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f5700000000000000000000000000000060208201526000908383019084821015612b6d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b509392505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052600090612bff8682612f31565b9695505050505050565b6000612c13610b93565b6001600160a01b03166308135a936040518163ffffffff1660e01b815260040160206040518083038186803b158015611d2857600080fd5b825460009081908190819067ffffffffffffffff620100008204169060ff16612c9257869350600092508291506001612c8a878663ffffffff612ae016565b039450612db7565b6000612c9e898861245a565b8954909150610100900460ff168015612cb957508682600101105b15612d8257600454909350915082612cd7838263ffffffff612ae016565b8810156040518060400160405280601d81526020017f43535f4c4f575f524553554d455f504552494f44535f5041594d454e5400000081525090612d5f57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5082880384900394506001612d7a888a63ffffffff612ae016565b039550612db5565b60009250612d96828963ffffffff612ae016565b955087811115612dac5760009450879350612db5565b80880394508093505b505b85851115612e5a57600354612dd2868863ffffffff612fa416565b106040518060400160405280601a81526020017f43535f504159494e475f544f4f5f4d414e595f504552494f445300000000000081525090612e5857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b505b5093509350935093565b600082612e7357506000611672565b82820282848281612e8057fe5b04146040518060400160405280601181526020017f4d4154485f4d554c5f4f564552464c4f5700000000000000000000000000000081525090612b6d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b6000612710612f228461ffff8516830163ffffffff612e6416565b81612f2957fe5b049392505050565b6000806040516020818551602087016000895af18015612f72573d8015612f5f5760208114612f6857612f70565b60019350612f70565b600183511493505b505b5090949350505050565b61271061ffff82161115919050565b6000612710612f228461ffff851663ffffffff612e6416565b6000828211156040518060400160405280601281526020017f4d4154485f5355425f554e444552464c4f5700000000000000000000000000008152509061302f57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5050900390565b60008054611672906130739067ffffffffffffffff858116917401000000000000000000000000000000000000000090041663ffffffff61318d16565b60019063ffffffff6130d416565b4390565b60008060009054906101000a90046001600160a01b03166001600160a01b031663953e46a06040518163ffffffff1660e01b815260040160206040518083038186803b158015611d2857600080fd5b60408051808201909152601381527f4d41544836345f4144445f4f564552464c4f570000000000000000000000000060208201526000908383019067ffffffffffffffff8086169083161015612b6d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b60006001600160a01b03821661318657506000610ea8565b503b151590565b60408051808201909152601381527f4d41544836345f4d554c5f4f564552464c4f5700000000000000000000000000602082015260009067ffffffffffffffff8481169084160290680100000000000000008210612b6d57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561089857818101518382015260200161088056fea165627a7a723058208a3aa8ef2209e2ecff24e03cffd11015e7bf6384bd545d40a537f14e87141c420029000000000000000000000000ee4650cbe7a2b23701d416f58b41d8b76b617797000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000008ac7230489e80000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061020b5760003560e01c8063831918821161012a578063de974ba4116100bd578063f06392671161008c578063fcdecfd011610071578063fcdecfd014610650578063fd13b07d14610658578063fd8e3934146106755761020b565b8063f063926714610616578063f14faf6f146106335761020b565b8063de974ba41461053e578063ded774291461056a578063e786a53914610587578063e8f45561146105c75761020b565b8063b2eed6dd116100f9578063b2eed6dd146104dd578063b470aade146104e5578063bf416be61461050a578063d49e3c88146105365761020b565b806383191882146104665780638456cb591461048c5780638f904a2114610494578063ac68a748146104c05761020b565b8063396b6247116101a2578063689e770011610171578063689e7700146103df5780636b392680146104005780637b8bc6451461041d578063830257371461045e5761020b565b8063396b624714610343578063414000b51461034b5780635a7dca57146103685780635abf3838146103875761020b565b80632d725d06116101de5780632d725d06146102f55780632db9d4f41461030f5780633018205f1461031757806338ca029a1461033b5761020b565b8063086146d2146102105780630a771c251461025657806324ae6a27146102a457806329577d51146102d4575b600080fd5b61021861069b565b604080516001600160a01b039096168652602086019490945267ffffffffffffffff9092168484015260608401526080830152519081900360a00190f35b61027c6004803603602081101561026c57600080fd5b50356001600160a01b03166106fd565b604080516001600160a01b039094168452602084019290925282820152519081900360600190f35b6102d2600480360360408110156102ba57600080fd5b506001600160a01b038135811691602001351661078f565b005b6102d2600480360360208110156102ea57600080fd5b503561ffff16610ad9565b6102fd610b87565b60408051918252519081900360200190f35b6102fd610b8d565b61031f610b93565b604080516001600160a01b039092168252519081900360200190f35b6102fd610ba2565b6102fd610ba8565b6102d26004803603602081101561036157600080fd5b5035610bb7565b610370610c8e565b6040805161ffff9092168252519081900360200190f35b6103ad6004803603602081101561039d57600080fd5b50356001600160a01b0316610cb8565b604080519415158552921515602085015267ffffffffffffffff91821684840152166060830152519081900360800190f35b6102d2600480360360208110156103f557600080fd5b503561ffff16610d04565b6102d26004803603602081101561041657600080fd5b5035610daf565b61043a6004803603602081101561043357600080fd5b5035610e5a565b6040805167ffffffffffffffff909316835260208301919091528051918290030190f35b6102fd610e70565b6102fd6004803603602081101561047c57600080fd5b50356001600160a01b0316610e76565b6102d2610ead565b61027c600480360360408110156104aa57600080fd5b506001600160a01b038135169060200135610fc6565b6102d2600480360360208110156104d657600080fd5b5035611026565b61031f611328565b6104ed611337565b6040805167ffffffffffffffff9092168252519081900360200190f35b6102d26004803603604081101561052057600080fd5b506001600160a01b03813516906020013561135f565b6102d2611417565b6102d26004803603604081101561055457600080fd5b506001600160a01b0381351690602001356114ad565b6102d26004803603602081101561058057600080fd5b503561159d565b6105b36004803603604081101561059d57600080fd5b506001600160a01b038135169060200135611648565b604080519115158252519081900360200190f35b6105f3600480360360408110156105dd57600080fd5b506001600160a01b038135169060200135611678565b604080516001600160a01b03909316835260208301919091528051918290030190f35b6102d26004803603602081101561062c57600080fd5b50356116dc565b6102d26004803603602081101561064957600080fd5b5035611787565b61037061192a565b61043a6004803603602081101561066e57600080fd5b5035611956565b6105b36004803603602081101561068b57600080fd5b50356001600160a01b031661197a565b6000806000806000806106ac6119d5565b60009081526007602052604090208054600182015460028301546003909301546001600160a01b03680100000000000000008404169a91995067ffffffffffffffff90921697509195509350915050565b6001600160a01b038116600090815260066020526040812081908190816107226119d5565b905060006107308383611adc565b60008381526007602052604081209192509061074b90611b67565b9097509050816107725783546000965062010000900467ffffffffffffffff169450610784565b61077e84838584611ba9565b90965094505b505050509193909250565b6000809054906101000a90046001600160a01b03166001600160a01b0316633c28e88b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156107dc57600080fd5b505afa1580156107f0573d6000803e3d6000fd5b505050506040513d602081101561080657600080fd5b505160408051808201909152601d81527f4354445f53454e4445525f4e4f545f46554e44535f474f5645524e4f520000006020820152906001600160a01b031633146108d357604051600160e51b62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610898578181015183820152602001610880565b50505050905090810190601f1680156108c55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290516000916001600160a01b038516916370a0823191602480820192602092909190829003018186803b15801561093757600080fd5b505afa15801561094b573d6000803e3d6000fd5b505050506040513d602081101561096157600080fd5b505160408051808201909152601e81527f4354445f494e53554646494349454e545f5245434f5645525f46554e445300006020820152909150816109e957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610a046001600160a01b038416838363ffffffff611c4e16565b6040518060400160405280601e81526020017f4354445f5245434f5645525f544f4b454e5f46554e44535f4641494c4544000081525090610a8957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50604080516001600160a01b0380861682528416602082015280820183905290517f724139fea3954691c2c1ee02b3be6be1763b32ec84841f1acad6d3a18695ba0d9181900360600190a1505050565b610ae1611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f52000081525090610b7a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610b8481611d59565b50565b60025481565b60045481565b6000546001600160a01b031690565b60035481565b6000610bb26119d5565b905090565b3360009081526006602090815260409182902080548351808501909452601a84527f43535f535542534352495054494f4e5f4e4f545f504155534544000000000000928401929092529190610100900460ff16610c5857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610c6581333385611ea2565b80547fffffffffffffffffffffffffffff0000000000000000ffffffffffffffff00ff16905550565b6000547c0100000000000000000000000000000000000000000000000000000000900461ffff1681565b6001600160a01b031660009081526006602052604090205460ff8082169261010083049091169167ffffffffffffffff6201000082048116926a01000000000000000000009092041690565b610d0c611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f52000081525090610da557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610b848161211d565b610db7611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f52000081525090610e5057604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610b84816121d5565b600080610e668361229b565b915091505b915091565b60055481565b6001600160a01b038116600090815260066020526040812081610e976119d5565b9050610ea3828261245a565b925050505b919050565b3360009081526006602090815260409182902080548351808501909452601884527f43535f53454e4445525f4e4f545f53554253435249424544000000000000000092840192909252919060ff16610f4957604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610f5b81610f566119d5565b61245a565b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff67ffffffffffffffff929092166a0100000000000000000000027fffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffff9091161716610100179055565b6001600160a01b03821660009081526006602052604081208190819081610feb6119d5565b60008181526007602052604081209192509061100690611b67565b909650905061101783888484611ba9565b96999098509596505050505050565b61102e6119d5565b81106040518060400160405280601281526020017f43535f4e4f4e5f504153545f504552494f440000000000000000000000000000815250906110b557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50600081815260076020908152604080832033845260048101835292819020548151808301909252601d82527f43535f4a55524f525f464545535f414c52454144595f434c41494d4544000000928201929092529060ff161561115c57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5060008061116a84846124eb565b91509150600061117c3385858561255a565b9050600081116040518060400160405280601981526020017f43535f4a55524f525f4e4f5448494e475f544f5f434c41494d000000000000008152509061120757604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5033600081815260048601602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055815184815291518893927f1ac537f0ad67b64ac68a04587ff3a4cb6977de22eb2c37ee560897a92c6d07c792908290030190a3835461129b906801000000000000000090046001600160a01b03163383611c4e565b6040518060400160405280601881526020017f43535f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509061132057604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b505050505050565b6001546001600160a01b031681565b60005474010000000000000000000000000000000000000000900467ffffffffffffffff1681565b611367611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f5200008152509061140057604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5061140a82612648565b611413816121d5565b5050565b6000600554116040518060400160405280601b81526020017f43535f474f5645524e4f525f53484152455f464545535f5a45524f0000000000815250906114a257604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b506114ab612769565b565b6001600160a01b03821660009081526006602090815260409182902080548351808501909452601684527f43535f535542534352495054494f4e5f50415553454400000000000000000000928401929092529190610100900460ff161561155857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5061156581338585611ea2565b805460ff166115985780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781555b505050565b6115a5611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f5200008152509061163e57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610b848161284e565b60008181526007602090815260408083206001600160a01b038616845260040190915290205460ff165b92915050565b600081815260076020526040812060028101548291908290806116a85761169e8661229b565b90925090506116b7565b825467ffffffffffffffff1691505b6116c38784848461255a565b93506116ce83611b67565b509793965092945050505050565b6116e4611cd9565b6001600160a01b0316336001600160a01b0316146040518060400160405280601e81526020017f4354445f53454e4445525f4e4f545f434f4e4649475f474f5645524e4f5200008152509061177d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50610b84816129a0565b60408051808201909152601781527f43535f444f4e4154494f4e5f414d4f554e545f5a45524f00000000000000000060208201528161180a57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5060006118156119d5565b600081815260076020526040812091925061182f82612a6e565b506003830154909150611848908563ffffffff612ae016565b600383015560408051858152905133917f27ef414ce6fa80a9350ddb76cf40cdd3f926f1d61450480b3cd52e7c889a1f93919081900360200190a261189e6001600160a01b03821633308763ffffffff612b7516565b6040518060400160405280601881526020017f43535f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509061192357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5050505050565b6000547e01000000000000000000000000000000000000000000000000000000000000900461ffff1681565b6000818152600760205260408120819061197084826124eb565b9250925050915091565b6001600160a01b0381166000908152600660205260408120805460ff1680156119aa57508054610100900460ff16155b80156119ce57506119b96119d5565b815462010000900467ffffffffffffffff1610155b9392505050565b6000806119e0612c09565b905060008167ffffffffffffffff16116040518060400160405280601881526020017f43535f434f5552545f4841535f4e4f545f53544152544544000000000000000081525090611a7557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b506000805467ffffffffffffffff740100000000000000000000000000000000000000009091048116907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84011681611aca57fe5b0467ffffffffffffffff169392505050565b815460009060ff16611af057506001611672565b825462010000900467ffffffffffffffff166000611b0e858561245a565b8554909150610100900460ff168015611b2957508382600101105b15611b4a57600454611b41908263ffffffff612ae016565b92505050611672565b838210611b5c57600092505050611672565b600101949350505050565b80546801000000000000000090046001600160a01b0316600081611b9e5750506001546002546001600160a01b0390911690610e6b565b506001820154915091565b600080808080611bba898989612c4b565b929650909450925090506000611be687611bda868563ffffffff612ae016565b9063ffffffff612e6416565b6000805491925090611c2c907c0100000000000000000000000000000000000000000000000000000000900461ffff16611c20868b612e64565b9063ffffffff612f0716565b9050611c3e828263ffffffff612ae016565b9650505050505094509492505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600090611cd08582612f31565b95945050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166397023f816040518163ffffffff1660e01b815260040160206040518083038186803b158015611d2857600080fd5b505afa158015611d3c573d6000803e3d6000fd5b505050506040513d6020811015611d5257600080fd5b5051905090565b611d6281612f7c565b6040518060400160405280601f81526020017f43535f4f56455252415445445f474f5645524e4f525f53484152455f5043540081525090611de757604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b506000546040805161ffff7e0100000000000000000000000000000000000000000000000000000000000090930483168152918316602083015280517f16b68bb17a802748657198a6c1752356706af9761fed9a0aec01e18dbab22e3d9281900390910190a16000805461ffff9092167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60408051808201909152601681527f43535f504159494e475f5a45524f5f504552494f445300000000000000000000602082015281611f2557604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b506000611f306119d5565b600081815260076020526040812091925080611f4b83612a6e565b91509150600080611f5e8a888886611ba9565b6000805492945090925090611f9a9084907e01000000000000000000000000000000000000000000000000000000000000900461ffff16612f8b565b600554909150611fb0908263ffffffff612ae016565b6005556000611fc5848363ffffffff612fa416565b6003880154909150611fdd908263ffffffff612ae016565b60038801558b5467ffffffffffffffff841662010000027fffffffffffffffffffffffffffffffffffffffffffff0000000000000000ffff909116178c55604080518a8152602081018590528082018390526060810184905290516001600160a01b038c16917f490965cdfe01182ccdb9781fc760b4655fbf35e70e531d1572fd0bb96adb92b7919081900360800190a26120896001600160a01b0387168c308763ffffffff612b7516565b6040518060400160405280601881526020017f43535f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509061210e57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50505050505050505050505050565b6000546040805161ffff7c010000000000000000000000000000000000000000000000000000000090930483168152918316602083015280517f95b30c5823523338cceacb3f088dd8ddba9e49ecf086cd8311cc9f2a51755e5f9281900390910190a16000805461ffff9092167c0100000000000000000000000000000000000000000000000000000000027fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60408051808201909152601281527f43535f4645455f414d4f554e545f5a45524f000000000000000000000000000060208201528161225857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50600254604080519182526020820183905280517f628999ddb8cc6bb99cec0350ca6e43277be4a15b13e849d3e532cada20effa829281900390910190a1600255565b60008060006122a984613036565b905060006122c66122c186600163ffffffff612ae016565b613036565b905060006122d2610b93565b90506000816001600160a01b03166361f3be6a846040518263ffffffff1660e01b8152600401808267ffffffffffffffff1667ffffffffffffffff16815260200191505060206040518083038186803b15801561232e57600080fd5b505afa158015612342573d6000803e3d6000fd5b505050506040513d602081101561235857600080fd5b505190508061237057600161236b613081565b034090505b600061237a613085565b6000549091506123c79074010000000000000000000000000000000000000000900467ffffffffffffffff1683816123ae57fe5b67ffffffffffffffff881691900663ffffffff6130d416565b9650806001600160a01b0316638e127793886040518263ffffffff1660e01b8152600401808267ffffffffffffffff1667ffffffffffffffff16815260200191505060206040518083038186803b15801561242157600080fd5b505afa158015612435573d6000803e3d6000fd5b505050506040513d602081101561244b57600080fd5b50519698969750505050505050565b815460009060ff1661246e57506000611672565b8254610100900460ff161561249d575081546a0100000000000000000000900467ffffffffffffffff16611672565b825462010000900467ffffffffffffffff168281106124c0576000915050611672565b9091037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b600281015460009080612544576125018461229b565b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff8316178555600285018190559092509050612553565b825467ffffffffffffffff1691505b9250929050565b600080612565613085565b604080517fe9e67d670000000000000000000000000000000000000000000000000000000081526001600160a01b03898116600483015267ffffffffffffffff8816602483015291519293506000929184169163e9e67d6791604480820192602092909190829003018186803b1580156125de57600080fd5b505afa1580156125f2573d6000803e3d6000fd5b505050506040513d602081101561260857600080fd5b505190508061261c57600092505050612640565b60038601548490612633908363ffffffff612e6416565b8161263a57fe5b04925050505b949350505050565b6126518161316e565b6040518060400160405280601981526020017f43535f4645455f544f4b454e5f4e4f545f434f4e545241435400000000000000815250906126d657604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50600554156126e7576126e7612769565b600154604080516001600160a01b039283168152918316602083015280517f1080b8de45190ac9d8745f3724225c9b50b849890e73595c4403edd52b9493709281900390910190a1600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6005805460009091556040805182815290517f8d4b456a5bf2af7af0c51b59d87fd03dec21a0d682d194c3181d3597962d2a6d9181900360200190a16127c96127b0611cd9565b6001546001600160a01b0316908363ffffffff611c4e16565b6040518060400160405280601881526020017f43535f544f4b454e5f5452414e534645525f4641494c454400000000000000008152509061141357604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b60408051808201909152601a81527f43535f5052455041594d454e545f504552494f44535f5a45524f0000000000006020820152816128d157604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b506004548110156040518060400160405280601e81526020017f43535f524553554d455f5052455f504149445f504552494f44535f42494700008152509061295d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50600354604080519182526020820183905280517f4250689f302002c7a5d16d204db28ba5f50190081ed4fa93e6254c1db1ebe1419281900390910190a1600355565b6003548111156040518060400160405280601e81526020017f43535f524553554d455f5052455f504149445f504552494f44535f424947000081525090612a2b57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b50600454604080519182526020820183905280517fec8da95e790f837a162434052aacad1a02c3ac922306093a55b37d08bc189d1d9281900390910190a1600455565b80546801000000000000000090046001600160a01b0316600081611b9e5750506001805482547fffffffff0000000000000000000000000000000000000000ffffffffffffffff166001600160a01b039091166801000000000000000081029190911783556002549290910182905591565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f5700000000000000000000000000000060208201526000908383019084821015612b6d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b509392505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052600090612bff8682612f31565b9695505050505050565b6000612c13610b93565b6001600160a01b03166308135a936040518163ffffffff1660e01b815260040160206040518083038186803b158015611d2857600080fd5b825460009081908190819067ffffffffffffffff620100008204169060ff16612c9257869350600092508291506001612c8a878663ffffffff612ae016565b039450612db7565b6000612c9e898861245a565b8954909150610100900460ff168015612cb957508682600101105b15612d8257600454909350915082612cd7838263ffffffff612ae016565b8810156040518060400160405280601d81526020017f43535f4c4f575f524553554d455f504552494f44535f5041594d454e5400000081525090612d5f57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5082880384900394506001612d7a888a63ffffffff612ae016565b039550612db5565b60009250612d96828963ffffffff612ae016565b955087811115612dac5760009450879350612db5565b80880394508093505b505b85851115612e5a57600354612dd2868863ffffffff612fa416565b106040518060400160405280601a81526020017f43535f504159494e475f544f4f5f4d414e595f504552494f445300000000000081525090612e5857604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b505b5093509350935093565b600082612e7357506000611672565b82820282848281612e8057fe5b04146040518060400160405280601181526020017f4d4154485f4d554c5f4f564552464c4f5700000000000000000000000000000081525090612b6d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b6000612710612f228461ffff8516830163ffffffff612e6416565b81612f2957fe5b049392505050565b6000806040516020818551602087016000895af18015612f72573d8015612f5f5760208114612f6857612f70565b60019350612f70565b600183511493505b505b5090949350505050565b61271061ffff82161115919050565b6000612710612f228461ffff851663ffffffff612e6416565b6000828211156040518060400160405280601281526020017f4d4154485f5355425f554e444552464c4f5700000000000000000000000000008152509061302f57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b5050900390565b60008054611672906130739067ffffffffffffffff858116917401000000000000000000000000000000000000000090041663ffffffff61318d16565b60019063ffffffff6130d416565b4390565b60008060009054906101000a90046001600160a01b03166001600160a01b031663953e46a06040518163ffffffff1660e01b815260040160206040518083038186803b158015611d2857600080fd5b60408051808201909152601381527f4d41544836345f4144445f4f564552464c4f570000000000000000000000000060208201526000908383019067ffffffffffffffff8086169083161015612b6d57604051600160e51b62461bcd028152602060048201818152835160248401528351909283926044909101919085019080838360008315610898578181015183820152602001610880565b60006001600160a01b03821661318657506000610ea8565b503b151590565b60408051808201909152601381527f4d41544836345f4d554c5f4f564552464c4f5700000000000000000000000000602082015260009067ffffffffffffffff8481169084160290680100000000000000008210612b6d57604051600160e51b62461bcd02815260206004820181815283516024840152835190928392604490910191908501908083836000831561089857818101518382015260200161088056fea165627a7a723058208a3aa8ef2209e2ecff24e03cffd11015e7bf6384bd545d40a537f14e87141c420029
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ee4650cbe7a2b23701d416f58b41d8b76b617797000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000008ac7230489e80000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _controller (address): 0xee4650cBe7a2B23701D416f58b41D8B76b617797
Arg [1] : _periodDuration (uint64): 90
Arg [2] : _feeToken (address): 0x6B175474E89094C44Da98b954EedeAC495271d0F
Arg [3] : _feeAmount (uint256): 10000000000000000000
Arg [4] : _prePaymentPeriods (uint256): 12
Arg [5] : _resumePrePaidPeriods (uint256): 12
Arg [6] : _latePaymentPenaltyPct (uint16): 1000
Arg [7] : _governorSharePct (uint16): 0
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000ee4650cbe7a2b23701d416f58b41d8b76b617797
Arg [1] : 000000000000000000000000000000000000000000000000000000000000005a
Arg [2] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [3] : 0000000000000000000000000000000000000000000000008ac7230489e80000
Arg [4] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [6] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000000
Swarm Source
bzzr://8a3aa8ef2209e2ecff24e03cffd11015e7bf6384bd545d40a537f14e87141c42
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.999868 | 4,111.4103 | $4,110.87 |
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.