Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 10815833 | 1503 days ago | IN | 0 ETH | 0.77518583 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
DelegationController
Compiler Version
v0.6.10+commit.00c0fcaf
Contract Source Code (Solidity Multiple files format)
// SPDX-License-Identifier: AGPL-3.0-only /* DelegationController.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev @author Vadim Yavorsky SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./IERC777.sol"; import "./Permissions.sol"; import "./Nodes.sol"; import "./MathUtils.sol"; import "./FractionUtils.sol"; import "./DelegationPeriodManager.sol"; import "./Punisher.sol"; import "./TokenLaunchLocker.sol"; import "./TokenState.sol"; import "./ValidatorService.sol"; import "./PartialDifferences.sol"; /** * @title Delegation Controller * @dev This contract performs all delegation functions including delegation * requests, undelegation, slashing, etc. * * Delegators and validators may both perform delegations. Validators who perform * delegations to themselves are effectively self-delegating or self-bonding. * * Delegated tokens may be in one of several states: * * - PROPOSED: token holder proposes tokens to delegate to a validator * - ACCEPTED: token delegations are accepted by a validator and are locked-by-delegation * - CANCELED: token holder cancels delegation proposal. Only allowed before the proposal is accepted by the validator * - REJECTED: token proposal expires at the UTC start of the next month * - DELEGATED: accepted delegations are delegated at the UTC start of the month * - UNDELEGATION_REQUESTED: token holder requests delegations to undelegate from the validator * - COMPLETED: undelegation request is completed at the end of the delegation period */ contract DelegationController is Permissions, ILocker { using MathUtils for uint; using PartialDifferences for PartialDifferences.Sequence; using PartialDifferences for PartialDifferences.Value; using FractionUtils for FractionUtils.Fraction; enum State { PROPOSED, ACCEPTED, CANCELED, REJECTED, DELEGATED, UNDELEGATION_REQUESTED, COMPLETED } struct Delegation { address holder; // address of token owner uint validatorId; uint amount; uint delegationPeriod; uint created; // time of delegation creation uint started; // month when a delegation becomes active uint finished; // first month after a delegation ends string info; } struct SlashingLogEvent { FractionUtils.Fraction reducingCoefficient; uint nextMonth; } struct SlashingLog { // month => slashing event mapping (uint => SlashingLogEvent) slashes; uint firstMonth; uint lastMonth; } struct DelegationExtras { uint lastSlashingMonthBeforeDelegation; } struct SlashingEvent { FractionUtils.Fraction reducingCoefficient; uint validatorId; uint month; } struct SlashingSignal { address holder; uint penalty; } struct LockedInPending { uint amount; uint month; } struct FirstDelegationMonth { // month uint value; //validatorId => month mapping (uint => uint) byValidator; } struct ValidatorsStatistics { // number of validators uint number; //validatorId => bool - is Delegated or not mapping (uint => uint) delegated; } /** * @dev Emitted when a delegation is proposed to a validator. */ event DelegationProposed( uint delegationId ); /** * @dev Emitted when a delegation is accepted by a validator. */ event DelegationAccepted( uint delegationId ); /** * @dev Emitted when a delegation is cancelled by the delegator. */ event DelegationRequestCanceledByUser( uint delegationId ); /** * @dev Emitted when a delegation is requested to undelegate. */ event UndelegationRequested( uint delegationId ); /// @dev delegations will never be deleted to index in this array may be used like delegation id Delegation[] public delegations; // validatorId => delegationId[] mapping (uint => uint[]) public delegationsByValidator; // holder => delegationId[] mapping (address => uint[]) public delegationsByHolder; // delegationId => extras mapping(uint => DelegationExtras) private _delegationExtras; // validatorId => sequence mapping (uint => PartialDifferences.Value) private _delegatedToValidator; // validatorId => sequence mapping (uint => PartialDifferences.Sequence) private _effectiveDelegatedToValidator; // validatorId => slashing log mapping (uint => SlashingLog) private _slashesOfValidator; // holder => sequence mapping (address => PartialDifferences.Value) private _delegatedByHolder; // holder => validatorId => sequence mapping (address => mapping (uint => PartialDifferences.Value)) private _delegatedByHolderToValidator; // holder => validatorId => sequence mapping (address => mapping (uint => PartialDifferences.Sequence)) private _effectiveDelegatedByHolderToValidator; SlashingEvent[] private _slashes; // holder => index in _slashes; mapping (address => uint) private _firstUnprocessedSlashByHolder; // holder => validatorId => month mapping (address => FirstDelegationMonth) private _firstDelegationMonth; // holder => locked in pending mapping (address => LockedInPending) private _lockedInPendingDelegations; mapping (address => ValidatorsStatistics) private _numberOfValidatorsPerDelegator; /** * @dev Modifier to make a function callable only if delegation exists. */ modifier checkDelegationExists(uint delegationId) { require(delegationId < delegations.length, "Delegation does not exist"); _; } function getAndUpdateDelegatedToValidatorNow(uint validatorId) external returns (uint) { return getAndUpdateDelegatedToValidator(validatorId, _getCurrentMonth()); } function getAndUpdateDelegatedAmount(address holder) external returns (uint) { return _getAndUpdateDelegatedByHolder(holder); } function getAndUpdateEffectiveDelegatedByHolderToValidator(address holder, uint validatorId, uint month) external allow("Distributor") returns (uint effectiveDelegated) { SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(holder); effectiveDelegated = _effectiveDelegatedByHolderToValidator[holder][validatorId] .getAndUpdateValueInSequence(month); _sendSlashingSignals(slashingSignals); } /** * @dev Allows a token holder to create a delegation proposal of an `amount` * and `delegationPeriod` to a `validatorId`. Delegation must be accepted * by the validator before the UTC start of the month, otherwise the * delegation will be rejected. * * The token holder may add additional information in each proposal. * * @param validatorId uint ID of validator to receive delegation proposal * @param amount uint amount of proposed delegation * @param delegationPeriod uint period of proposed delegation * @param info string extra information provided by the token holder (if any) */ function delegate( uint validatorId, uint amount, uint delegationPeriod, string calldata info ) external { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); DelegationPeriodManager delegationPeriodManager = DelegationPeriodManager( contractManager.getContract("DelegationPeriodManager")); IERC777 skaleToken = IERC777(contractManager.getContract("SkaleToken")); TokenState tokenState = TokenState(contractManager.getContract("TokenState")); require( validatorService.checkMinimumDelegation(validatorId, amount), "Amount does not meet the validator's minimum delegation amount"); require( validatorService.isAuthorizedValidator(validatorId), "Validator is not authorized to accept delegation request"); require( delegationPeriodManager.isDelegationPeriodAllowed(delegationPeriod), "This delegation period is not allowed"); require( validatorService.isAcceptingNewRequests(validatorId), "The validator is not currently accepting new requests"); _checkIfDelegationIsAllowed(msg.sender, validatorId); SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(msg.sender); uint delegationId = _addDelegation( msg.sender, validatorId, amount, delegationPeriod, info); // check that there is enough money uint holderBalance = skaleToken.balanceOf(msg.sender); uint forbiddenForDelegation = tokenState.getAndUpdateForbiddenForDelegationAmount(msg.sender); require(holderBalance >= forbiddenForDelegation, "Token holder does not have enough tokens to delegate"); emit DelegationProposed(delegationId); _sendSlashingSignals(slashingSignals); } /** * @dev See ILocker. */ function getAndUpdateLockedAmount(address wallet) external override returns (uint) { return _getAndUpdateLockedAmount(wallet); } /** * @dev See ILocker. */ function getAndUpdateForbiddenForDelegationAmount(address wallet) external override returns (uint) { return _getAndUpdateLockedAmount(wallet); } /** * @dev Allows a token holder to cancel a delegation proposal. * * Requirements: * * - the sender must be the token holder of the delegation proposal. * - the delegation must still be in a PROPOSED state. * * Emits a DelegationRequestCanceledByUser event. * * @param delegationId uint ID of delegation proposal */ function cancelPendingDelegation(uint delegationId) external checkDelegationExists(delegationId) { require(msg.sender == delegations[delegationId].holder, "Only token holders can cancel delegation request"); require(getState(delegationId) == State.PROPOSED, "Token holders are only able to cancel PROPOSED delegations"); delegations[delegationId].finished = _getCurrentMonth(); _subtractFromLockedInPendingDelegations(delegations[delegationId].holder, delegations[delegationId].amount); emit DelegationRequestCanceledByUser(delegationId); } /** * @dev Allows a validator to accept a proposed delegation. * Successful acceptance of delegations transition the tokens from a * PROPOSED state to ACCEPTED, and tokens are locked for the remainder of the * delegation period. * * Emits a DelegationAccepted event. * * @param delegationId uint ID of delegation proposal */ function acceptPendingDelegation(uint delegationId) external checkDelegationExists(delegationId) { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); require( validatorService.checkValidatorAddressToId(msg.sender, delegations[delegationId].validatorId), "No permissions to accept request"); _checkIfDelegationIsAllowed(delegations[delegationId].holder, delegations[delegationId].validatorId); State currentState = getState(delegationId); if (currentState != State.PROPOSED) { if (currentState == State.ACCEPTED || currentState == State.DELEGATED || currentState == State.UNDELEGATION_REQUESTED || currentState == State.COMPLETED) { revert("The delegation has been already accepted"); } else if (currentState == State.CANCELED) { revert("The delegation has been cancelled by token holder"); } else if (currentState == State.REJECTED) { revert("The delegation request is outdated"); } } require(currentState == State.PROPOSED, "Cannot set delegation state to accepted"); TokenLaunchLocker tokenLaunchLocker = TokenLaunchLocker(contractManager.getContract("TokenLaunchLocker")); SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(delegations[delegationId].holder); _addToAllStatistics(delegationId); tokenLaunchLocker.handleDelegationAdd( delegations[delegationId].holder, delegationId, delegations[delegationId].amount, delegations[delegationId].started); _sendSlashingSignals(slashingSignals); emit DelegationAccepted(delegationId); } /** * @dev Allows a delegator to undelegate a specific delegation. * * Requirements: * * - the sender must be the delegator. * - the delegation must be in DELEGATED state. * * Emits an UndelegationRequested event. * * @param delegationId uint ID of delegation to undelegate */ function requestUndelegation(uint delegationId) external checkDelegationExists(delegationId) { require(getState(delegationId) == State.DELEGATED, "Cannot request undelegation"); ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); require( delegations[delegationId].holder == msg.sender || (validatorService.validatorAddressExists(msg.sender) && delegations[delegationId].validatorId == validatorService.getValidatorId(msg.sender)), "Permission denied to request undelegation"); TokenLaunchLocker tokenLaunchLocker = TokenLaunchLocker(contractManager.getContract("TokenLaunchLocker")); DelegationPeriodManager delegationPeriodManager = DelegationPeriodManager( contractManager.getContract("DelegationPeriodManager")); _removeValidatorFromValidatorsPerDelegators( delegations[delegationId].holder, delegations[delegationId].validatorId ); processAllSlashes(msg.sender); delegations[delegationId].finished = _calculateDelegationEndMonth(delegationId); uint amountAfterSlashing = _calculateDelegationAmountAfterSlashing(delegationId); _removeFromDelegatedToValidator( delegations[delegationId].validatorId, amountAfterSlashing, delegations[delegationId].finished); _removeFromDelegatedByHolder( delegations[delegationId].holder, amountAfterSlashing, delegations[delegationId].finished); _removeFromDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, amountAfterSlashing, delegations[delegationId].finished); uint effectiveAmount = amountAfterSlashing.mul(delegationPeriodManager.stakeMultipliers( delegations[delegationId].delegationPeriod)); _removeFromEffectiveDelegatedToValidator( delegations[delegationId].validatorId, effectiveAmount, delegations[delegationId].finished); _removeFromEffectiveDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, effectiveAmount, delegations[delegationId].finished); tokenLaunchLocker.handleDelegationRemoving( delegations[delegationId].holder, delegationId, delegations[delegationId].finished); emit UndelegationRequested(delegationId); } /** * @dev Allows the Punisher to confiscate an `amount` of stake from * `validatorId` by slashing. This slashes all delegations of the validator, * which reduces the amount that the validator has staked. This consequence * may force the SKALE Manger to reduce the number of nodes a validator is * operating so the validator can meet the Minimum Staking Requirement. * * See Punisher. * * Emits a SlashingEvent. * * @param validatorId uint validator to slash * @param amount uint amount to slash * */ function confiscate(uint validatorId, uint amount) external allow("Punisher") { uint currentMonth = _getCurrentMonth(); FractionUtils.Fraction memory coefficient = _delegatedToValidator[validatorId].reduceValue(amount, currentMonth); _effectiveDelegatedToValidator[validatorId].reduceSequence(coefficient, currentMonth); _putToSlashingLog(_slashesOfValidator[validatorId], coefficient, currentMonth); _slashes.push(SlashingEvent({reducingCoefficient: coefficient, validatorId: validatorId, month: currentMonth})); } function getAndUpdateEffectiveDelegatedToValidator(uint validatorId, uint month) external allow("Distributor") returns (uint) { return _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(month); } function getAndUpdateDelegatedByHolderToValidatorNow(address holder, uint validatorId) external returns (uint) { return _getAndUpdateDelegatedByHolderToValidator(holder, validatorId, _getCurrentMonth()); } function getDelegation(uint delegationId) external view checkDelegationExists(delegationId) returns (Delegation memory) { return delegations[delegationId]; } function getFirstDelegationMonth(address holder, uint validatorId) external view returns(uint) { return _firstDelegationMonth[holder].byValidator[validatorId]; } function getDelegationsByValidatorLength(uint validatorId) external view returns (uint) { return delegationsByValidator[validatorId].length; } function getDelegationsByHolderLength(address holder) external view returns (uint) { return delegationsByHolder[holder].length; } function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); } function getAndUpdateDelegatedToValidator(uint validatorId, uint month) public allow("Nodes") returns (uint) { return _delegatedToValidator[validatorId].getAndUpdateValue(month); } function processSlashes(address holder, uint limit) public { _sendSlashingSignals(_processSlashesWithoutSignals(holder, limit)); } function processAllSlashes(address holder) public { processSlashes(holder, 0); } /** * @dev Returns the token state of a given delegation. * * @param delegationId uint ID of the delegation */ function getState(uint delegationId) public view checkDelegationExists(delegationId) returns (State state) { if (delegations[delegationId].started == 0) { if (delegations[delegationId].finished == 0) { TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); if (_getCurrentMonth() == timeHelpers.timestampToMonth(delegations[delegationId].created)) { return State.PROPOSED; } else { return State.REJECTED; } } else { return State.CANCELED; } } else { if (_getCurrentMonth() < delegations[delegationId].started) { return State.ACCEPTED; } else { if (delegations[delegationId].finished == 0) { return State.DELEGATED; } else { if (_getCurrentMonth() < delegations[delegationId].finished) { return State.UNDELEGATION_REQUESTED; } else { return State.COMPLETED; } } } } } function getLockedInPendingDelegations(address holder) public view returns (uint) { uint currentMonth = _getCurrentMonth(); if (_lockedInPendingDelegations[holder].month < currentMonth) { return 0; } else { return _lockedInPendingDelegations[holder].amount; } } function hasUnprocessedSlashes(address holder) public view returns (bool) { return _everDelegated(holder) && _firstUnprocessedSlashByHolder[holder] < _slashes.length; } // private function _addDelegation( address holder, uint validatorId, uint amount, uint delegationPeriod, string memory info ) private returns (uint delegationId) { delegationId = delegations.length; delegations.push(Delegation( holder, validatorId, amount, delegationPeriod, now, 0, 0, info )); delegationsByValidator[validatorId].push(delegationId); delegationsByHolder[holder].push(delegationId); _addToLockedInPendingDelegations(delegations[delegationId].holder, delegations[delegationId].amount); } function _calculateDelegationEndMonth(uint delegationId) private view returns (uint) { uint currentMonth = _getCurrentMonth(); uint started = delegations[delegationId].started; if (currentMonth < started) { return started.add(delegations[delegationId].delegationPeriod); } else { uint completedPeriods = currentMonth.sub(started).div(delegations[delegationId].delegationPeriod); return started.add(completedPeriods.add(1).mul(delegations[delegationId].delegationPeriod)); } } function _addToDelegatedToValidator(uint validatorId, uint amount, uint month) private { _delegatedToValidator[validatorId].addToValue(amount, month); } function _addToEffectiveDelegatedToValidator(uint validatorId, uint effectiveAmount, uint month) private { _effectiveDelegatedToValidator[validatorId].addToSequence(effectiveAmount, month); } function _addToDelegatedByHolder(address holder, uint amount, uint month) private { _delegatedByHolder[holder].addToValue(amount, month); } function _addToDelegatedByHolderToValidator( address holder, uint validatorId, uint amount, uint month) private { _delegatedByHolderToValidator[holder][validatorId].addToValue(amount, month); } function _addValidatorToValidatorsPerDelegators(address holder, uint validatorId) private { if (_numberOfValidatorsPerDelegator[holder].delegated[validatorId] == 0) { _numberOfValidatorsPerDelegator[holder].number = _numberOfValidatorsPerDelegator[holder].number.add(1); } _numberOfValidatorsPerDelegator[holder]. delegated[validatorId] = _numberOfValidatorsPerDelegator[holder].delegated[validatorId].add(1); } function _removeFromDelegatedByHolder(address holder, uint amount, uint month) private { _delegatedByHolder[holder].subtractFromValue(amount, month); } function _removeFromDelegatedByHolderToValidator( address holder, uint validatorId, uint amount, uint month) private { _delegatedByHolderToValidator[holder][validatorId].subtractFromValue(amount, month); } function _removeValidatorFromValidatorsPerDelegators(address holder, uint validatorId) private { if (_numberOfValidatorsPerDelegator[holder].delegated[validatorId] == 1) { _numberOfValidatorsPerDelegator[holder].number = _numberOfValidatorsPerDelegator[holder].number.sub(1); } _numberOfValidatorsPerDelegator[holder]. delegated[validatorId] = _numberOfValidatorsPerDelegator[holder].delegated[validatorId].sub(1); } function _addToEffectiveDelegatedByHolderToValidator( address holder, uint validatorId, uint effectiveAmount, uint month) private { _effectiveDelegatedByHolderToValidator[holder][validatorId].addToSequence(effectiveAmount, month); } function _removeFromEffectiveDelegatedByHolderToValidator( address holder, uint validatorId, uint effectiveAmount, uint month) private { _effectiveDelegatedByHolderToValidator[holder][validatorId].subtractFromSequence(effectiveAmount, month); } function _getAndUpdateDelegatedByHolder(address holder) private returns (uint) { uint currentMonth = _getCurrentMonth(); processAllSlashes(holder); return _delegatedByHolder[holder].getAndUpdateValue(currentMonth); } function _getAndUpdateDelegatedByHolderToValidator( address holder, uint validatorId, uint month) private returns (uint) { return _delegatedByHolderToValidator[holder][validatorId].getAndUpdateValue(month); } function _addToLockedInPendingDelegations(address holder, uint amount) private returns (uint) { uint currentMonth = _getCurrentMonth(); if (_lockedInPendingDelegations[holder].month < currentMonth) { _lockedInPendingDelegations[holder].amount = amount; _lockedInPendingDelegations[holder].month = currentMonth; } else { assert(_lockedInPendingDelegations[holder].month == currentMonth); _lockedInPendingDelegations[holder].amount = _lockedInPendingDelegations[holder].amount.add(amount); } } function _subtractFromLockedInPendingDelegations(address holder, uint amount) private returns (uint) { uint currentMonth = _getCurrentMonth(); require( _lockedInPendingDelegations[holder].month == currentMonth, "There are no delegation requests this month"); require(_lockedInPendingDelegations[holder].amount >= amount, "Unlocking amount is too big"); _lockedInPendingDelegations[holder].amount = _lockedInPendingDelegations[holder].amount.sub(amount); } function _getCurrentMonth() private view returns (uint) { TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); return timeHelpers.getCurrentMonth(); } function _getAndUpdateLockedAmount(address wallet) private returns (uint) { return _getAndUpdateDelegatedByHolder(wallet).add(getLockedInPendingDelegations(wallet)); } function _updateFirstDelegationMonth(address holder, uint validatorId, uint month) private { if (_firstDelegationMonth[holder].value == 0) { _firstDelegationMonth[holder].value = month; _firstUnprocessedSlashByHolder[holder] = _slashes.length; } if (_firstDelegationMonth[holder].byValidator[validatorId] == 0) { _firstDelegationMonth[holder].byValidator[validatorId] = month; } } function _everDelegated(address holder) private view returns (bool) { return _firstDelegationMonth[holder].value > 0; } function _removeFromDelegatedToValidator(uint validatorId, uint amount, uint month) private { _delegatedToValidator[validatorId].subtractFromValue(amount, month); } function _removeFromEffectiveDelegatedToValidator(uint validatorId, uint effectiveAmount, uint month) private { _effectiveDelegatedToValidator[validatorId].subtractFromSequence(effectiveAmount, month); } function _calculateDelegationAmountAfterSlashing(uint delegationId) private view returns (uint) { uint startMonth = _delegationExtras[delegationId].lastSlashingMonthBeforeDelegation; uint validatorId = delegations[delegationId].validatorId; uint amount = delegations[delegationId].amount; if (startMonth == 0) { startMonth = _slashesOfValidator[validatorId].firstMonth; if (startMonth == 0) { return amount; } } for (uint i = startMonth; i > 0 && i < delegations[delegationId].finished; i = _slashesOfValidator[validatorId].slashes[i].nextMonth) { if (i >= delegations[delegationId].started) { amount = amount .mul(_slashesOfValidator[validatorId].slashes[i].reducingCoefficient.numerator) .div(_slashesOfValidator[validatorId].slashes[i].reducingCoefficient.denominator); } } return amount; } function _putToSlashingLog( SlashingLog storage log, FractionUtils.Fraction memory coefficient, uint month) private { if (log.firstMonth == 0) { log.firstMonth = month; log.lastMonth = month; log.slashes[month].reducingCoefficient = coefficient; log.slashes[month].nextMonth = 0; } else { require(log.lastMonth <= month, "Cannot put slashing event in the past"); if (log.lastMonth == month) { log.slashes[month].reducingCoefficient = log.slashes[month].reducingCoefficient.multiplyFraction(coefficient); } else { log.slashes[month].reducingCoefficient = coefficient; log.slashes[month].nextMonth = 0; log.slashes[log.lastMonth].nextMonth = month; log.lastMonth = month; } } } function _processSlashesWithoutSignals(address holder, uint limit) private returns (SlashingSignal[] memory slashingSignals) { if (hasUnprocessedSlashes(holder)) { uint index = _firstUnprocessedSlashByHolder[holder]; uint end = _slashes.length; if (limit > 0 && index.add(limit) < end) { end = index.add(limit); } slashingSignals = new SlashingSignal[](end.sub(index)); uint begin = index; for (; index < end; ++index) { uint validatorId = _slashes[index].validatorId; uint month = _slashes[index].month; uint oldValue = _getAndUpdateDelegatedByHolderToValidator(holder, validatorId, month); if (oldValue.muchGreater(0)) { _delegatedByHolderToValidator[holder][validatorId].reduceValueByCoefficientAndUpdateSum( _delegatedByHolder[holder], _slashes[index].reducingCoefficient, month); _effectiveDelegatedByHolderToValidator[holder][validatorId].reduceSequence( _slashes[index].reducingCoefficient, month); slashingSignals[index.sub(begin)].holder = holder; slashingSignals[index.sub(begin)].penalty = oldValue.boundedSub(_getAndUpdateDelegatedByHolderToValidator(holder, validatorId, month)); } } _firstUnprocessedSlashByHolder[holder] = end; } } function _processAllSlashesWithoutSignals(address holder) private returns (SlashingSignal[] memory slashingSignals) { return _processSlashesWithoutSignals(holder, 0); } function _sendSlashingSignals(SlashingSignal[] memory slashingSignals) private { Punisher punisher = Punisher(contractManager.getContract("Punisher")); address previousHolder = address(0); uint accumulatedPenalty = 0; for (uint i = 0; i < slashingSignals.length; ++i) { if (slashingSignals[i].holder != previousHolder) { if (accumulatedPenalty > 0) { punisher.handleSlash(previousHolder, accumulatedPenalty); } previousHolder = slashingSignals[i].holder; accumulatedPenalty = slashingSignals[i].penalty; } else { accumulatedPenalty = accumulatedPenalty.add(slashingSignals[i].penalty); } } if (accumulatedPenalty > 0) { punisher.handleSlash(previousHolder, accumulatedPenalty); } } function _addToAllStatistics(uint delegationId) private { DelegationPeriodManager delegationPeriodManager = DelegationPeriodManager( contractManager.getContract("DelegationPeriodManager")); uint currentMonth = _getCurrentMonth(); delegations[delegationId].started = currentMonth.add(1); if (_slashesOfValidator[delegations[delegationId].validatorId].lastMonth > 0) { _delegationExtras[delegationId].lastSlashingMonthBeforeDelegation = _slashesOfValidator[delegations[delegationId].validatorId].lastMonth; } _addToDelegatedToValidator( delegations[delegationId].validatorId, delegations[delegationId].amount, currentMonth.add(1)); _addToDelegatedByHolder( delegations[delegationId].holder, delegations[delegationId].amount, currentMonth.add(1)); _addToDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, delegations[delegationId].amount, currentMonth.add(1)); _updateFirstDelegationMonth( delegations[delegationId].holder, delegations[delegationId].validatorId, currentMonth.add(1)); uint effectiveAmount = delegations[delegationId].amount.mul(delegationPeriodManager.stakeMultipliers( delegations[delegationId].delegationPeriod)); _addToEffectiveDelegatedToValidator( delegations[delegationId].validatorId, effectiveAmount, currentMonth.add(1)); _addToEffectiveDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, effectiveAmount, currentMonth.add(1)); _addValidatorToValidatorsPerDelegators( delegations[delegationId].holder, delegations[delegationId].validatorId ); } function _checkIfDelegationIsAllowed(address holder, uint validatorId) private view returns (bool) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); require( _numberOfValidatorsPerDelegator[holder].delegated[validatorId] > 0 || ( _numberOfValidatorsPerDelegator[holder].delegated[validatorId] == 0 && _numberOfValidatorsPerDelegator[holder].number < constantsHolder.limitValidatorsPerDelegator() ), "Limit of validators is reached" ); } }
pragma solidity ^0.6.0; import "./EnumerableSet.sol"; import "./Address.sol"; import "./Context.sol"; import "./Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, _msgSender())); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. */ abstract contract AccessControlUpgradeSafe is Initializable, ContextUpgradeSafe { function __AccessControl_init() internal initializer { __Context_init_unchained(); __AccessControl_init_unchained(); } function __AccessControl_init_unchained() internal initializer { } using EnumerableSet for EnumerableSet.AddressSet; using Address for address; struct RoleData { EnumerableSet.AddressSet members; bytes32 adminRole; } mapping (bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view returns (bool) { return _roles[role].members.contains(account); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view returns (uint256) { return _roles[role].members.length(); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view returns (address) { return _roles[role].members.at(index); } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant"); _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke"); _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) public virtual { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { _roles[role].adminRole = adminRole; } function _grantRole(bytes32 role, address account) private { if (_roles[role].members.add(account)) { emit RoleGranted(role, account, _msgSender()); } } function _revokeRole(bytes32 role, address account) private { if (_roles[role].members.remove(account)) { emit RoleRevoked(role, account, _msgSender()); } } uint256[49] private __gap; }
pragma solidity ^0.6.2; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } }
pragma solidity ^0.6.0; // ---------------------------------------------------------------------------- // BokkyPooBah's DateTime Library v1.01 // // A gas-efficient Solidity date and time library // // https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary // // Tested date range 1970/01/01 to 2345/12/31 // // Conventions: // Unit | Range | Notes // :-------- |:-------------:|:----- // timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC // year | 1970 ... 2345 | // month | 1 ... 12 | // day | 1 ... 31 | // hour | 0 ... 23 | // minute | 0 ... 59 | // second | 0 ... 59 | // dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday // // // Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. // ---------------------------------------------------------------------------- library BokkyPooBahsDateTimeLibrary { uint constant SECONDS_PER_DAY = 24 * 60 * 60; uint constant SECONDS_PER_HOUR = 60 * 60; uint constant SECONDS_PER_MINUTE = 60; int constant OFFSET19700101 = 2440588; uint constant DOW_MON = 1; uint constant DOW_TUE = 2; uint constant DOW_WED = 3; uint constant DOW_THU = 4; uint constant DOW_FRI = 5; uint constant DOW_SAT = 6; uint constant DOW_SUN = 7; // ------------------------------------------------------------------------ // Calculate the number of days from 1970/01/01 to year/month/day using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and subtracting the offset 2440588 so that 1970/01/01 is day 0 // // days = day // - 32075 // + 1461 * (year + 4800 + (month - 14) / 12) / 4 // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 // - offset // ------------------------------------------------------------------------ function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { require(year >= 1970); int _year = int(year); int _month = int(month); int _day = int(day); int __days = _day - 32075 + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 - OFFSET19700101; _days = uint(__days); } // ------------------------------------------------------------------------ // Calculate year/month/day from the number of days since 1970/01/01 using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and adding the offset 2440588 so that 1970/01/01 is day 0 // // int L = days + 68569 + offset // int N = 4 * L / 146097 // L = L - (146097 * N + 3) / 4 // year = 4000 * (L + 1) / 1461001 // L = L - 1461 * year / 4 + 31 // month = 80 * L / 2447 // dd = L - 2447 * month / 80 // L = month / 11 // month = month + 2 - 12 * L // year = 100 * (N - 49) + year + L // ------------------------------------------------------------------------ function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { int __days = int(_days); int L = __days + 68569 + OFFSET19700101; int N = 4 * L / 146097; L = L - (146097 * N + 3) / 4; int _year = 4000 * (L + 1) / 1461001; L = L - 1461 * _year / 4 + 31; int _month = 80 * L / 2447; int _day = L - 2447 * _month / 80; L = _month / 11; _month = _month + 2 - 12 * L; _year = 100 * (N - 49) + _year + L; year = uint(_year); month = uint(_month); day = uint(_day); } function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; } function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; } function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); uint secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; secs = secs % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; second = secs % SECONDS_PER_MINUTE; } function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) { if (year >= 1970 && month > 0 && month <= 12) { uint daysInMonth = _getDaysInMonth(year, month); if (day > 0 && day <= daysInMonth) { valid = true; } } } function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) { if (isValidDate(year, month, day)) { if (hour < 24 && minute < 60 && second < 60) { valid = true; } } } function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { uint year; uint month; uint day; (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); leapYear = _isLeapYear(year); } function _isLeapYear(uint year) internal pure returns (bool leapYear) { leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); } function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { weekDay = getDayOfWeek(timestamp) <= DOW_FRI; } function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; } function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { uint year; uint month; uint day; (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); daysInMonth = _getDaysInMonth(year, month); } function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { daysInMonth = 31; } else if (month != 2) { daysInMonth = 30; } else { daysInMonth = _isLeapYear(year) ? 29 : 28; } } // 1 = Monday, 7 = Sunday function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { uint _days = timestamp / SECONDS_PER_DAY; dayOfWeek = (_days + 3) % 7 + 1; } function getYear(uint timestamp) internal pure returns (uint year) { uint month; uint day; (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getMonth(uint timestamp) internal pure returns (uint month) { uint year; uint day; (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getDay(uint timestamp) internal pure returns (uint day) { uint year; uint month; (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getHour(uint timestamp) internal pure returns (uint hour) { uint secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; } function getMinute(uint timestamp) internal pure returns (uint minute) { uint secs = timestamp % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; } function getSecond(uint timestamp) internal pure returns (uint second) { second = timestamp % SECONDS_PER_MINUTE; } function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { uint year; uint month; uint day; (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); year += _years; uint daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { uint year; uint month; uint day; (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); month += _months; year += (month - 1) / 12; month = (month - 1) % 12 + 1; uint daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _days * SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; require(newTimestamp >= timestamp); } function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; require(newTimestamp >= timestamp); } function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _seconds; require(newTimestamp >= timestamp); } function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { uint year; uint month; uint day; (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); year -= _years; uint daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; require(newTimestamp <= timestamp); } function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { uint year; uint month; uint day; (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); uint yearMonth = year * 12 + (month - 1) - _months; year = yearMonth / 12; month = yearMonth % 12 + 1; uint daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; require(newTimestamp <= timestamp); } function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _days * SECONDS_PER_DAY; require(newTimestamp <= timestamp); } function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; require(newTimestamp <= timestamp); } function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; require(newTimestamp <= timestamp); } function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _seconds; require(newTimestamp <= timestamp); } function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { require(fromTimestamp <= toTimestamp); uint fromYear; uint fromMonth; uint fromDay; uint toYear; uint toMonth; uint toDay; (fromYear, fromMonth, fromDay) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); (toYear, toMonth, toDay) = _daysToDate(toTimestamp / SECONDS_PER_DAY); _years = toYear - fromYear; } function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { require(fromTimestamp <= toTimestamp); uint fromYear; uint fromMonth; uint fromDay; uint toYear; uint toMonth; uint toDay; (fromYear, fromMonth, fromDay) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); (toYear, toMonth, toDay) = _daysToDate(toTimestamp / SECONDS_PER_DAY); _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; } function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { require(fromTimestamp <= toTimestamp); _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; } function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { require(fromTimestamp <= toTimestamp); _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; } function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { require(fromTimestamp <= toTimestamp); _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; } function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { require(fromTimestamp <= toTimestamp); _seconds = toTimestamp - fromTimestamp; } }
// SPDX-License-Identifier: AGPL-3.0-only /* Bounty.sol - SKALE Manager Copyright (C) 2020-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./ConstantsHolder.sol"; import "./Nodes.sol"; import "./Permissions.sol"; contract Bounty is Permissions { uint public constant STAGE_LENGTH = 31558150; // 1 year uint public constant YEAR1_BOUNTY = 3850e5 * 1e18; uint public constant YEAR2_BOUNTY = 3465e5 * 1e18; uint public constant YEAR3_BOUNTY = 3080e5 * 1e18; uint public constant YEAR4_BOUNTY = 2695e5 * 1e18; uint public constant YEAR5_BOUNTY = 2310e5 * 1e18; uint public constant YEAR6_BOUNTY = 1925e5 * 1e18; uint public constant BOUNTY = 96250000 * 1e18; uint private _nextStage; uint private _stagePool; bool public bountyReduction; uint private _nodesPerRewardPeriod; uint private _nodesRemainingPerRewardPeriod; uint private _rewardPeriodFinished; function getBounty( uint nodeIndex, uint downtime, uint latency ) external allow("SkaleManager") returns (uint) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); Nodes nodes = Nodes(contractManager.getContract("Nodes")); _refillStagePool(constantsHolder); if (_rewardPeriodFinished <= now) { _updateNodesPerRewardPeriod(constantsHolder, nodes); } uint bounty = _calculateMaximumBountyAmount(_stagePool, _nextStage, nodeIndex, constantsHolder, nodes); bounty = _reduceBounty( bounty, nodeIndex, downtime, latency, nodes, constantsHolder ); _stagePool = _stagePool.sub(bounty); _nodesRemainingPerRewardPeriod = _nodesRemainingPerRewardPeriod.sub(1); return bounty; } function enableBountyReduction() external onlyOwner { bountyReduction = true; } function disableBountyReduction() external onlyOwner { bountyReduction = false; } function calculateNormalBounty(uint nodeIndex) external view returns (uint) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); Nodes nodes = Nodes(contractManager.getContract("Nodes")); uint stagePoolSize; uint nextStage; (stagePoolSize, nextStage) = _getStagePoolSize(constantsHolder); return _calculateMaximumBountyAmount( stagePoolSize, nextStage, nodeIndex, constantsHolder, nodes ); } function initialize(address contractManagerAddress) public override initializer { Permissions.initialize(contractManagerAddress); _nextStage = 0; _stagePool = 0; _rewardPeriodFinished = 0; bountyReduction = false; } // private function _calculateMaximumBountyAmount( uint stagePoolSize, uint nextStage, uint nodeIndex, ConstantsHolder constantsHolder, Nodes nodes ) private view returns (uint) { if (nodes.isNodeLeft(nodeIndex)) { return 0; } if (now < constantsHolder.launchTimestamp()) { // network is not launched // bounty is turned off return 0; } uint numberOfRewards = _getStageBeginningTimestamp(nextStage, constantsHolder) .sub(now) .div(constantsHolder.rewardPeriod()); uint numberOfRewardsPerAllNodes = numberOfRewards.mul(_nodesPerRewardPeriod); return stagePoolSize.div( numberOfRewardsPerAllNodes.add(_nodesRemainingPerRewardPeriod) ); } function _getStageBeginningTimestamp(uint stage, ConstantsHolder constantsHolder) private view returns (uint) { return constantsHolder.launchTimestamp().add(stage.mul(STAGE_LENGTH)); } function _getStagePoolSize(ConstantsHolder constantsHolder) private view returns (uint stagePool, uint nextStage) { stagePool = _stagePool; for (nextStage = _nextStage; now >= _getStageBeginningTimestamp(nextStage, constantsHolder); ++nextStage) { stagePool += _getStageReward(_nextStage); } } function _refillStagePool(ConstantsHolder constantsHolder) private { (_stagePool, _nextStage) = _getStagePoolSize(constantsHolder); } function _updateNodesPerRewardPeriod(ConstantsHolder constantsHolder, Nodes nodes) private { _nodesPerRewardPeriod = nodes.getNumberOnlineNodes(); _nodesRemainingPerRewardPeriod = _nodesPerRewardPeriod; _rewardPeriodFinished = now.add(uint(constantsHolder.rewardPeriod())); } function _getStageReward(uint stage) private pure returns (uint) { if (stage >= 6) { return BOUNTY.div(2 ** stage.sub(6).div(3)); } else { if (stage == 0) { return YEAR1_BOUNTY; } else if (stage == 1) { return YEAR2_BOUNTY; } else if (stage == 2) { return YEAR3_BOUNTY; } else if (stage == 3) { return YEAR4_BOUNTY; } else if (stage == 4) { return YEAR5_BOUNTY; } else { return YEAR6_BOUNTY; } } } function _reduceBounty( uint bounty, uint nodeIndex, uint downtime, uint latency, Nodes nodes, ConstantsHolder constants ) private returns (uint reducedBounty) { if (!bountyReduction) { return bounty; } reducedBounty = _reduceBountyByDowntime(bounty, nodeIndex, downtime, nodes, constants); if (latency > constants.allowableLatency()) { // reduce bounty because latency is too big reducedBounty = reducedBounty.mul(constants.allowableLatency()).div(latency); } if (!nodes.checkPossibilityToMaintainNode(nodes.getValidatorId(nodeIndex), nodeIndex)) { reducedBounty = reducedBounty.div(constants.MSR_REDUCING_COEFFICIENT()); } } function _reduceBountyByDowntime( uint bounty, uint nodeIndex, uint downtime, Nodes nodes, ConstantsHolder constants ) private view returns (uint reducedBounty) { reducedBounty = bounty; uint getBountyDeadline = uint(nodes.getNodeLastRewardDate(nodeIndex)) .add(constants.rewardPeriod()) .add(constants.deltaPeriod()); uint numberOfExpiredIntervals; if (now > getBountyDeadline) { numberOfExpiredIntervals = now.sub(getBountyDeadline).div(constants.checkTime()); } else { numberOfExpiredIntervals = 0; } uint normalDowntime = uint(constants.rewardPeriod()) .sub(constants.deltaPeriod()) .div(constants.checkTime()) .div(constants.DOWNTIME_THRESHOLD_PART()); uint totalDowntime = downtime.add(numberOfExpiredIntervals); if (totalDowntime > normalDowntime) { // reduce bounty because downtime is too big uint penalty = bounty .mul(totalDowntime) .div( uint(constants.rewardPeriod()).sub(constants.deltaPeriod()) .div(constants.checkTime()) ); if (bounty > penalty) { reducedBounty = bounty.sub(penalty); } else { reducedBounty = 0; } } } }
// SPDX-License-Identifier: AGPL-3.0-only /* ConstantsHolder.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./Permissions.sol"; /** * @title Contains constants and common variables for Skale Manager system * @author Artem Payvin */ contract ConstantsHolder is Permissions { // initial price for creating Node (100 SKL) uint public constant NODE_DEPOSIT = 100 * 1e18; uint8 public constant TOTAL_SPACE_ON_NODE = 128; // part of Node for Small Skale-chain (1/128 of Node) uint8 public constant SMALL_DIVISOR = 128; // part of Node for Medium Skale-chain (1/8 of Node) uint8 public constant MEDIUM_DIVISOR = 8; // part of Node for Large Skale-chain (full Node) uint8 public constant LARGE_DIVISOR = 1; // part of Node for Medium Test Skale-chain (1/4 of Node) uint8 public constant MEDIUM_TEST_DIVISOR = 4; // typically number of Nodes for Skale-chain (16 Nodes) uint public constant NUMBER_OF_NODES_FOR_SCHAIN = 16; // number of Nodes for Test Skale-chain (2 Nodes) uint public constant NUMBER_OF_NODES_FOR_TEST_SCHAIN = 2; // number of Nodes for Test Skale-chain (4 Nodes) uint public constant NUMBER_OF_NODES_FOR_MEDIUM_TEST_SCHAIN = 4; // number of seconds in one year uint32 public constant SECONDS_TO_YEAR = 31622400; // initial number of monitors uint public constant NUMBER_OF_MONITORS = 24; uint public constant OPTIMAL_LOAD_PERCENTAGE = 80; uint public constant ADJUSTMENT_SPEED = 1000; uint public constant COOLDOWN_TIME = 60; uint public constant MIN_PRICE = 10**6; uint public constant MSR_REDUCING_COEFFICIENT = 2; uint public constant DOWNTIME_THRESHOLD_PART = 30; uint public constant BOUNTY_LOCKUP_MONTHS = 2; // MSR - Minimum staking requirement uint public msr; // Reward period - 30 days (each 30 days Node would be granted for bounty) uint32 public rewardPeriod; // Allowable latency - 150000 ms by default uint32 public allowableLatency; /** * Delta period - 1 hour (1 hour before Reward period became Monitors need * to send Verdicts and 1 hour after Reward period became Node need to come * and get Bounty) */ uint32 public deltaPeriod; /** * Check time - 2 minutes (every 2 minutes monitors should check metrics * from checked nodes) */ uint public checkTime; //Need to add minimal allowed parameters for verdicts uint public launchTimestamp; uint public rotationDelay; uint public proofOfUseLockUpPeriodDays; uint public proofOfUseDelegationPercentage; uint public limitValidatorsPerDelegator; uint256 public firstDelegationsMonth; // deprecated // date when schains will be allowed for creation uint public schainCreationTimeStamp; uint public minimalSchainLifetime; /** * Set reward and delta periods to new one, run only by owner. This function * only for tests. * @param newRewardPeriod - new Reward period * @param newDeltaPeriod - new Delta period */ function setPeriods(uint32 newRewardPeriod, uint32 newDeltaPeriod) external onlyOwner { require( newRewardPeriod >= newDeltaPeriod && newRewardPeriod - newDeltaPeriod >= checkTime, "Incorrect Periods" ); rewardPeriod = newRewardPeriod; deltaPeriod = newDeltaPeriod; } /** * Set new check time. This function only for tests. * @param newCheckTime - new check time */ function setCheckTime(uint newCheckTime) external onlyOwner { require(rewardPeriod - deltaPeriod >= checkTime, "Incorrect check time"); checkTime = newCheckTime; } /** * Set latency new one in ms, run only by owner. This function * only for tests. * @param newAllowableLatency - new Allowable Latency */ function setLatency(uint32 newAllowableLatency) external onlyOwner { allowableLatency = newAllowableLatency; } function setMSR(uint newMSR) external onlyOwner { msr = newMSR; } function setLaunchTimestamp(uint timestamp) external onlyOwner { require(now < launchTimestamp, "Can't set network launch timestamp because network is already launched"); launchTimestamp = timestamp; } function setRotationDelay(uint newDelay) external onlyOwner { rotationDelay = newDelay; } function setProofOfUseLockUpPeriod(uint periodDays) external onlyOwner { proofOfUseLockUpPeriodDays = periodDays; } function setProofOfUseDelegationPercentage(uint percentage) external onlyOwner { require(percentage <= 100, "Percentage value is incorrect"); proofOfUseDelegationPercentage = percentage; } function setLimitValidatorsPerDelegator(uint newLimit) external onlyOwner { limitValidatorsPerDelegator = newLimit; } function setSchainCreationTimeStamp(uint timestamp) external onlyOwner { schainCreationTimeStamp = timestamp; } function setMinimalSchainLifetime(uint lifetime) external onlyOwner { minimalSchainLifetime = lifetime; } /** * @dev constructor in Permissions approach * @param contractsAddress needed in Permissions constructor */ function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); msr = 0; rewardPeriod = 2592000; allowableLatency = 150000; deltaPeriod = 3600; checkTime = 300; launchTimestamp = uint(-1); rotationDelay = 12 hours; proofOfUseLockUpPeriodDays = 90; proofOfUseDelegationPercentage = 50; limitValidatorsPerDelegator = 20; firstDelegationsMonth = 0; } }
pragma solidity ^0.6.0; import "./Initializable.sol"; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract ContextUpgradeSafe is Initializable { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } uint256[50] private __gap; }
// SPDX-License-Identifier: AGPL-3.0-only /* ContractManager.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./Ownable.sol"; import "./Address.sol"; import "./StringUtils.sol"; /** * @title Main contract in upgradeable approach. This contract contains the actual * current mapping from contract IDs (in the form of human-readable strings) to addresses. * @author Artem Payvin */ contract ContractManager is OwnableUpgradeSafe { using StringUtils for string; using Address for address; // mapping of actual smart contracts addresses mapping (bytes32 => address) public contracts; event ContractUpgraded(string contractsName, address contractsAddress); function initialize() external initializer { OwnableUpgradeSafe.__Ownable_init(); } /** * Adds actual contract to mapping of actual contract addresses * @param contractsName - contracts name in skale manager system * @param newContractsAddress - contracts address in skale manager system */ function setContractsAddress(string calldata contractsName, address newContractsAddress) external onlyOwner { // check newContractsAddress is not equal to zero require(newContractsAddress != address(0), "New address is equal zero"); // create hash of contractsName bytes32 contractId = keccak256(abi.encodePacked(contractsName)); // check newContractsAddress is not equal the previous contract's address require(contracts[contractId] != newContractsAddress, "Contract is already added"); require(newContractsAddress.isContract(), "Given contracts address does not contain code"); // add newContractsAddress to mapping of actual contract addresses contracts[contractId] = newContractsAddress; emit ContractUpgraded(contractsName, newContractsAddress); } function getContract(string calldata name) external view returns (address contractAddress) { contractAddress = contracts[keccak256(abi.encodePacked(name))]; require(contractAddress != address(0), name.strConcat(" contract has not been found")); } }
// SPDX-License-Identifier: AGPL-3.0-only /* Decryption.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; contract Decryption { function encrypt(uint256 secretNumber, bytes32 key) external pure returns (bytes32 ciphertext) { return bytes32(secretNumber) ^ key; } function decrypt(bytes32 ciphertext, bytes32 key) external pure returns (uint256 secretNumber) { return uint256(ciphertext ^ key); } }
// SPDX-License-Identifier: AGPL-3.0-only /* DelegationPeriodManager.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev @author Vadim Yavorsky SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./Permissions.sol"; /** * @title Delegation Period Manager * @dev This contract handles all delegation offerings. Delegations are held for * a specified period (months), and different durations can have different * returns or `stakeMultiplier`. Currently, only delegation periods can be added. */ contract DelegationPeriodManager is Permissions { /** * @dev Emitted when a new delegation period is specified. */ event DelegationPeriodWasSet( uint length, uint stakeMultiplier ); mapping (uint => uint) public stakeMultipliers; /** * @dev Creates a new available delegation period and return in the network. * Only the owner may set new delegation period and returns in the network. * * Emits a DelegationPeriodWasSet event. * * @param monthsCount uint delegation duration in months * @param stakeMultiplier uint return for delegation */ function setDelegationPeriod(uint monthsCount, uint stakeMultiplier) external onlyOwner { stakeMultipliers[monthsCount] = stakeMultiplier; emit DelegationPeriodWasSet(monthsCount, stakeMultiplier); } /** * @dev Checks whether given delegation period is allowed. * * @param monthsCount uint delegation duration in months * @return bool True if delegation period is allowed */ function isDelegationPeriodAllowed(uint monthsCount) external view returns (bool) { return stakeMultipliers[monthsCount] != 0 ? true : false; } /** * @dev Initial delegation period and multiplier settings. */ function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); stakeMultipliers[3] = 100; // 3 months at 100 // stakeMultipliers[6] = 150; // 6 months at 150 // stakeMultipliers[12] = 200; // 12 months at 200 } }
// SPDX-License-Identifier: AGPL-3.0-only /* Distributor.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./IERC1820Registry.sol"; import "./IERC777Recipient.sol"; import "./IERC20.sol"; import "./Permissions.sol"; import "./ConstantsHolder.sol"; import "./MathUtils.sol"; import "./ValidatorService.sol"; import "./DelegationController.sol"; import "./DelegationPeriodManager.sol"; import "./TimeHelpers.sol"; contract Distributor is Permissions, IERC777Recipient { using MathUtils for uint; /** * @dev Emitted when a bounty is withdrawn by the token holder. */ event WithdrawBounty( address holder, uint validatorId, address destination, uint amount ); /** * @dev Emitted when a validator fee is withdrawn by the validator. */ event WithdrawFee( uint validatorId, address destination, uint amount ); /** * @dev Emitted when a bounty is distributed. */ event BountyWasPaid( uint validatorId, uint amount ); IERC1820Registry private _erc1820; // validatorId => month => token mapping (uint => mapping (uint => uint)) private _bountyPaid; // validatorId => month => token mapping (uint => mapping (uint => uint)) private _feePaid; // holder => validatorId => month mapping (address => mapping (uint => uint)) private _firstUnwithdrawnMonth; // validatorId => month mapping (uint => uint) private _firstUnwithdrawnMonthForValidator; function getAndUpdateEarnedBountyAmount(uint validatorId) external returns (uint earned, uint endMonth) { return getAndUpdateEarnedBountyAmountOf(msg.sender, validatorId); } function withdrawBounty(uint validatorId, address to) external { TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); require(now >= timeHelpers.addMonths( constantsHolder.launchTimestamp(), constantsHolder.BOUNTY_LOCKUP_MONTHS() ), "Bounty is locked"); uint bounty; uint endMonth; (bounty, endMonth) = getAndUpdateEarnedBountyAmountOf(msg.sender, validatorId); _firstUnwithdrawnMonth[msg.sender][validatorId] = endMonth; IERC20 skaleToken = IERC20(contractManager.getContract("SkaleToken")); require(skaleToken.transfer(to, bounty), "Failed to transfer tokens"); emit WithdrawBounty( msg.sender, validatorId, to, bounty ); } function withdrawFee(address to) external { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); IERC20 skaleToken = IERC20(contractManager.getContract("SkaleToken")); TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); require(now >= timeHelpers.addMonths( constantsHolder.launchTimestamp(), constantsHolder.BOUNTY_LOCKUP_MONTHS() ), "Bounty is locked"); // check Validator Exist inside getValidatorId uint validatorId = validatorService.getValidatorId(msg.sender); uint fee; uint endMonth; (fee, endMonth) = getEarnedFeeAmountOf(validatorId); _firstUnwithdrawnMonthForValidator[validatorId] = endMonth; require(skaleToken.transfer(to, fee), "Failed to transfer tokens"); emit WithdrawFee( validatorId, to, fee ); } function tokensReceived( address, address, address to, uint256 amount, bytes calldata userData, bytes calldata ) external override allow("SkaleToken") { require(to == address(this), "Receiver is incorrect"); require(userData.length == 32, "Data length is incorrect"); uint validatorId = abi.decode(userData, (uint)); _distributeBounty(amount, validatorId); } function getEarnedFeeAmount() external view returns (uint earned, uint endMonth) { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); return getEarnedFeeAmountOf(validatorService.getValidatorId(msg.sender)); } function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); _erc1820.setInterfaceImplementer(address(this), keccak256("ERC777TokensRecipient"), address(this)); } function getAndUpdateEarnedBountyAmountOf(address wallet, uint validatorId) public returns (uint earned, uint endMonth) { DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController")); TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); uint currentMonth = timeHelpers.getCurrentMonth(); uint startMonth = _firstUnwithdrawnMonth[wallet][validatorId]; if (startMonth == 0) { startMonth = delegationController.getFirstDelegationMonth(wallet, validatorId); if (startMonth == 0) { return (0, 0); } } earned = 0; endMonth = currentMonth; if (endMonth > startMonth.add(12)) { endMonth = startMonth.add(12); } for (uint i = startMonth; i < endMonth; ++i) { uint effectiveDelegatedToValidator = delegationController.getAndUpdateEffectiveDelegatedToValidator(validatorId, i); if (effectiveDelegatedToValidator.muchGreater(0)) { earned = earned.add( _bountyPaid[validatorId][i].mul( delegationController.getAndUpdateEffectiveDelegatedByHolderToValidator(wallet, validatorId, i)) .div(effectiveDelegatedToValidator) ); } } } function getEarnedFeeAmountOf(uint validatorId) public view returns (uint earned, uint endMonth) { TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); uint currentMonth = timeHelpers.getCurrentMonth(); uint startMonth = _firstUnwithdrawnMonthForValidator[validatorId]; if (startMonth == 0) { return (0, 0); } earned = 0; endMonth = currentMonth; if (endMonth > startMonth.add(12)) { endMonth = startMonth.add(12); } for (uint i = startMonth; i < endMonth; ++i) { earned = earned.add(_feePaid[validatorId][i]); } } // private function _distributeBounty(uint amount, uint validatorId) private { TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); uint currentMonth = timeHelpers.getCurrentMonth(); uint feeRate = validatorService.getValidator(validatorId).feeRate; uint fee = amount.mul(feeRate).div(1000); uint bounty = amount.sub(fee); _bountyPaid[validatorId][currentMonth] = _bountyPaid[validatorId][currentMonth].add(bounty); _feePaid[validatorId][currentMonth] = _feePaid[validatorId][currentMonth].add(fee); if (_firstUnwithdrawnMonthForValidator[validatorId] == 0) { _firstUnwithdrawnMonthForValidator[validatorId] = currentMonth; } emit BountyWasPaid(validatorId, amount); } }
// SPDX-License-Identifier: AGPL-3.0-only /* ECDH.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR _A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./SafeMath.sol"; contract ECDH { using SafeMath for uint256; uint256 constant private _GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798; uint256 constant private _GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8; uint256 constant private _N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; uint256 constant private _A = 0; function publicKey(uint256 privKey) external pure returns (uint256 qx, uint256 qy) { uint256 x; uint256 y; uint256 z; (x, y, z) = ecMul( privKey, _GX, _GY, 1 ); z = inverse(z); qx = mulmod(x, z, _N); qy = mulmod(y, z, _N); } function deriveKey( uint256 privKey, uint256 pubX, uint256 pubY ) external pure returns (uint256 qx, uint256 qy) { uint256 x; uint256 y; uint256 z; (x, y, z) = ecMul( privKey, pubX, pubY, 1 ); z = inverse(z); qx = mulmod(x, z, _N); qy = mulmod(y, z, _N); } function jAdd( uint256 x1, uint256 z1, uint256 x2, uint256 z2 ) public pure returns (uint256 x3, uint256 z3) { (x3, z3) = (addmod(mulmod(z2, x1, _N), mulmod(x2, z1, _N), _N), mulmod(z1, z2, _N)); } function jSub( uint256 x1, uint256 z1, uint256 x2, uint256 z2 ) public pure returns (uint256 x3, uint256 z3) { (x3, z3) = (addmod(mulmod(z2, x1, _N), mulmod(_N.sub(x2), z1, _N), _N), mulmod(z1, z2, _N)); } function jMul( uint256 x1, uint256 z1, uint256 x2, uint256 z2 ) public pure returns (uint256 x3, uint256 z3) { (x3, z3) = (mulmod(x1, x2, _N), mulmod(z1, z2, _N)); } function jDiv( uint256 x1, uint256 z1, uint256 x2, uint256 z2 ) public pure returns (uint256 x3, uint256 z3) { (x3, z3) = (mulmod(x1, z2, _N), mulmod(z1, x2, _N)); } function inverse(uint256 a) public pure returns (uint256 invA) { uint256 t = 0; uint256 newT = 1; uint256 r = _N; uint256 newR = a; uint256 q; while (newR != 0) { q = r.div(newR); (t, newT) = (newT, addmod(t, (_N.sub(mulmod(q, newT, _N))), _N)); (r, newR) = (newR, r % newR); } return t; } function ecAdd( uint256 x1, uint256 y1, uint256 z1, uint256 x2, uint256 y2, uint256 z2 ) public pure returns (uint256 x3, uint256 y3, uint256 z3) { uint256 ln; uint256 lz; uint256 da; uint256 db; if ((x1 == 0) && (y1 == 0)) { return (x2, y2, z2); } if ((x2 == 0) && (y2 == 0)) { return (x1, y1, z1); } if ((x1 == x2) && (y1 == y2)) { (ln, lz) = jMul(x1, z1, x1, z1); (ln, lz) = jMul(ln,lz,3,1); (ln, lz) = jAdd(ln,lz,_A,1); (da, db) = jMul(y1,z1,2,1); } else { (ln, lz) = jSub(y2,z2,y1,z1); (da, db) = jSub(x2,z2,x1,z1); } (ln, lz) = jDiv(ln,lz,da,db); (x3, da) = jMul(ln,lz,ln,lz); (x3, da) = jSub(x3,da,x1,z1); (x3, da) = jSub(x3,da,x2,z2); (y3, db) = jSub(x1,z1,x3,da); (y3, db) = jMul(y3,db,ln,lz); (y3, db) = jSub(y3,db,y1,z1); if (da != db) { x3 = mulmod(x3, db, _N); y3 = mulmod(y3, da, _N); z3 = mulmod(da, db, _N); } else { z3 = da; } } function ecDouble( uint256 x1, uint256 y1, uint256 z1 ) public pure returns (uint256 x3, uint256 y3, uint256 z3) { (x3, y3, z3) = ecAdd( x1, y1, z1, x1, y1, z1 ); } function ecMul( uint256 d, uint256 x1, uint256 y1, uint256 z1 ) public pure returns (uint256 x3, uint256 y3, uint256 z3) { uint256 remaining = d; uint256 px = x1; uint256 py = y1; uint256 pz = z1; uint256 acx = 0; uint256 acy = 0; uint256 acz = 1; if (d == 0) { return (0, 0, 1); } while (remaining != 0) { if ((remaining & 1) != 0) { (acx, acy, acz) = ecAdd( acx, acy, acz, px, py, pz ); } remaining = remaining.div(2); (px, py, pz) = ecDouble(px, py, pz); } (x3, y3, z3) = (acx, acy, acz); } }
pragma solidity ^0.6.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { revert("ECDSA: invalid signature length"); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { revert("ECDSA: invalid signature 's' value"); } if (v != 27 && v != 28) { revert("ECDSA: invalid signature 'v' value"); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "ECDSA: invalid signature"); return signer; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } }
pragma solidity ^0.6.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256` * (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(value))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(value))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(value))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint256(_at(set._inner, index))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } }
// SPDX-License-Identifier: AGPL-3.0-only /* FieldOperations.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./SafeMath.sol"; import "./Precompiled.sol"; library Fp2Operations { using SafeMath for uint; struct Fp2Point { uint a; uint b; } uint constant public P = 21888242871839275222246405745257275088696311157297823662689037894645226208583; function addFp2(Fp2Point memory value1, Fp2Point memory value2) internal pure returns (Fp2Point memory) { return Fp2Point({ a: addmod(value1.a, value2.a, P), b: addmod(value1.b, value2.b, P) }); } function scalarMulFp2(Fp2Point memory value, uint scalar) internal pure returns (Fp2Point memory) { return Fp2Point({ a: mulmod(scalar, value.a, P), b: mulmod(scalar, value.b, P) }); } function minusFp2(Fp2Point memory diminished, Fp2Point memory subtracted) internal pure returns (Fp2Point memory difference) { uint p = P; if (diminished.a >= subtracted.a) { difference.a = addmod(diminished.a, p - (subtracted.a), p); } else { difference.a = p - (addmod(subtracted.a, p - (diminished.a), p)); } if (diminished.b >= subtracted.b) { difference.b = addmod(diminished.b, p - (subtracted.b), p); } else { difference.b = p - (addmod(subtracted.b, p - (diminished.b), p)); } } function mulFp2( Fp2Point memory value1, Fp2Point memory value2 ) internal pure returns (Fp2Point memory result) { uint p = P; Fp2Point memory point = Fp2Point({ a: mulmod(value1.a, value2.a, p), b: mulmod(value1.b, value2.b, p)}); result.a = addmod( point.a, mulmod(p - 1, point.b, p), p); result.b = addmod( mulmod( addmod(value1.a, value1.b, p), addmod(value2.a, value2.b, p), p), p - addmod(point.a, point.b, p), p); } function squaredFp2(Fp2Point memory value) internal pure returns (Fp2Point memory) { uint p = P; uint ab = mulmod(value.a, value.b, p); uint mult = mulmod(addmod(value.a, value.b, p), addmod(value.a, mulmod(p - 1, value.b, p), p), p); return Fp2Point({ a: mult, b: addmod(ab, ab, p) }); } function inverseFp2(Fp2Point memory value) internal view returns (Fp2Point memory result) { uint p = P; uint t0 = mulmod(value.a, value.a, p); uint t1 = mulmod(value.b, value.b, p); uint t2 = mulmod(p - 1, t1, p); if (t0 >= t2) { t2 = addmod(t0, p - t2, p); } else { t2 = p - addmod(t2, p - t0, p); } uint t3 = Precompiled.bigModExp(t2, p - 2, p); result.a = mulmod(value.a, t3, p); result.b = p - mulmod(value.b, t3, p); } function isEqual( Fp2Point memory value1, Fp2Point memory value2 ) internal pure returns (bool) { return value1.a == value2.a && value1.b == value2.b; } } library G2Operations { using SafeMath for uint; using Fp2Operations for Fp2Operations.Fp2Point; struct G2Point { Fp2Operations.Fp2Point x; Fp2Operations.Fp2Point y; } function getTWISTB() internal pure returns (Fp2Operations.Fp2Point memory) { // Current solidity version does not support Constants of non-value type // so we implemented this function return Fp2Operations.Fp2Point({ a: 19485874751759354771024239261021720505790618469301721065564631296452457478373, b: 266929791119991161246907387137283842545076965332900288569378510910307636690 }); } function getG2() internal pure returns (G2Point memory) { // Current solidity version does not support Constants of non-value type // so we implemented this function return G2Point({ x: Fp2Operations.Fp2Point({ a: 10857046999023057135944570762232829481370756359578518086990519993285655852781, b: 11559732032986387107991004021392285783925812861821192530917403151452391805634 }), y: Fp2Operations.Fp2Point({ a: 8495653923123431417604973247489272438418190587263600148770280649306958101930, b: 4082367875863433681332203403145435568316851327593401208105741076214120093531 }) }); } function getG1() internal pure returns (Fp2Operations.Fp2Point memory) { // Current solidity version does not support Constants of non-value type // so we implemented this function return Fp2Operations.Fp2Point({ a: 1, b: 2 }); } function getG2Zero() internal pure returns (G2Point memory) { // Current solidity version does not support Constants of non-value type // so we implemented this function return G2Point({ x: Fp2Operations.Fp2Point({ a: 0, b: 0 }), y: Fp2Operations.Fp2Point({ a: 1, b: 0 }) }); } function isG1Point(uint x, uint y) internal pure returns (bool) { uint p = Fp2Operations.P; return mulmod(y, y, p) == addmod(mulmod(mulmod(x, x, p), x, p), 3, p); } function isG1(Fp2Operations.Fp2Point memory point) internal pure returns (bool) { return isG1Point(point.a, point.b); } function isG2Point(Fp2Operations.Fp2Point memory x, Fp2Operations.Fp2Point memory y) internal pure returns (bool) { if (isG2ZeroPoint(x, y)) { return true; } Fp2Operations.Fp2Point memory squaredY = y.squaredFp2(); Fp2Operations.Fp2Point memory res = squaredY.minusFp2( x.squaredFp2().mulFp2(x) ).minusFp2(getTWISTB()); return res.a == 0 && res.b == 0; } function isG2(G2Point memory value) internal pure returns (bool) { return isG2Point(value.x, value.y); } function isG2ZeroPoint( Fp2Operations.Fp2Point memory x, Fp2Operations.Fp2Point memory y ) internal pure returns (bool) { return x.a == 0 && x.b == 0 && y.a == 1 && y.b == 0; } function isG2Zero(G2Point memory value) internal pure returns (bool) { return value.x.a == 0 && value.x.b == 0 && value.y.a == 1 && value.y.b == 0; // return isG2ZeroPoint(value.x, value.y); } function addG2( G2Point memory value1, G2Point memory value2 ) internal view returns (G2Point memory sum) { if (isG2Zero(value1)) { return value2; } if (isG2Zero(value2)) { return value1; } if (isEqual(value1, value2)) { return doubleG2(value1); } Fp2Operations.Fp2Point memory s = value2.y.minusFp2(value1.y).mulFp2(value2.x.minusFp2(value1.x).inverseFp2()); sum.x = s.squaredFp2().minusFp2(value1.x.addFp2(value2.x)); sum.y = value1.y.addFp2(s.mulFp2(sum.x.minusFp2(value1.x))); uint p = Fp2Operations.P; sum.y.a = p - sum.y.a; sum.y.b = p - sum.y.b; } function toUS(G2Point memory value) internal pure returns (G2Point memory) { return G2Point({ x: value.x.mulFp2(Fp2Operations.Fp2Point({ a: 1, b: 0 }).squaredFp2()), y: value.y.mulFp2( Fp2Operations.Fp2Point({ a: 1, b: 0 }).mulFp2(Fp2Operations.Fp2Point({ a: 1, b: 0 }).squaredFp2()) ) }); } function isEqual( G2Point memory value1, G2Point memory value2 ) internal pure returns (bool) { return value1.x.isEqual(value2.x) && value1.y.isEqual(value2.y); } function doubleG2(G2Point memory value) internal view returns (G2Point memory result) { if (isG2Zero(value)) { return value; } else { Fp2Operations.Fp2Point memory s = value.x.squaredFp2().scalarMulFp2(3).mulFp2(value.y.scalarMulFp2(2).inverseFp2()); result.x = s.squaredFp2().minusFp2(value.x.addFp2(value.x)); result.y = value.y.addFp2(s.mulFp2(result.x.minusFp2(value.x))); uint p = Fp2Operations.P; result.y.a = p - result.y.a; result.y.b = p - result.y.b; } } function mulG2( G2Point memory value, uint scalar ) internal view returns (G2Point memory result) { uint step = scalar; result = G2Point({ x: Fp2Operations.Fp2Point({ a: 0, b: 0 }), y: Fp2Operations.Fp2Point({ a: 1, b: 0 }) }); G2Point memory tmp = value; uint gs = gasleft(); while (step > 0) { if (step % 2 == 1) { result = addG2(result, tmp); } gs = gasleft(); tmp = doubleG2(tmp); step >>= 1; } } }
// SPDX-License-Identifier: AGPL-3.0-only /* FractionUtils.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./SafeMath.sol"; library FractionUtils { using SafeMath for uint; struct Fraction { uint numerator; uint denominator; } function createFraction(uint numerator, uint denominator) internal pure returns (Fraction memory) { require(denominator > 0, "Division by zero"); Fraction memory fraction = Fraction({numerator: numerator, denominator: denominator}); reduceFraction(fraction); return fraction; } function createFraction(uint value) internal pure returns (Fraction memory) { return createFraction(value, 1); } function reduceFraction(Fraction memory fraction) internal pure { uint _gcd = gcd(fraction.numerator, fraction.denominator); fraction.numerator = fraction.numerator.div(_gcd); fraction.denominator = fraction.denominator.div(_gcd); } function multiplyFraction(Fraction memory a, Fraction memory b) internal pure returns (Fraction memory) { return createFraction(a.numerator.mul(b.numerator), a.denominator.mul(b.denominator)); } function gcd(uint a, uint b) internal pure returns (uint) { uint _a = a; uint _b = b; if (_b > _a) { (_a, _b) = swap(_a, _b); } while (_b > 0) { _a = _a.mod(_b); (_a, _b) = swap (_a, _b); } return _a; } function swap(uint a, uint b) internal pure returns (uint, uint) { return (b, a); } }
pragma solidity ^0.6.0; /** * @dev Interface of the global ERC1820 Registry, as defined in the * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register * implementers for interfaces in this registry, as well as query support. * * Implementers may be shared by multiple accounts, and can also implement more * than a single interface for each account. Contracts can implement interfaces * for themselves, but externally-owned accounts (EOA) must delegate this to a * contract. * * {IERC165} interfaces can also be queried via the registry. * * For an in-depth explanation and source code analysis, see the EIP text. */ interface IERC1820Registry { /** * @dev Sets `newManager` as the manager for `account`. A manager of an * account is able to set interface implementers for it. * * By default, each account is its own manager. Passing a value of `0x0` in * `newManager` will reset the manager to this initial state. * * Emits a {ManagerChanged} event. * * Requirements: * * - the caller must be the current manager for `account`. */ function setManager(address account, address newManager) external; /** * @dev Returns the manager for `account`. * * See {setManager}. */ function getManager(address account) external view returns (address); /** * @dev Sets the `implementer` contract as ``account``'s implementer for * `interfaceHash`. * * `account` being the zero address is an alias for the caller's address. * The zero address can also be used in `implementer` to remove an old one. * * See {interfaceHash} to learn how these are created. * * Emits an {InterfaceImplementerSet} event. * * Requirements: * * - the caller must be the current manager for `account`. * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not * end in 28 zeroes). * - `implementer` must implement {IERC1820Implementer} and return true when * queried for support, unless `implementer` is the caller. See * {IERC1820Implementer-canImplementInterfaceForAddress}. */ function setInterfaceImplementer(address account, bytes32 interfaceHash, address implementer) external; /** * @dev Returns the implementer of `interfaceHash` for `account`. If no such * implementer is registered, returns the zero address. * * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28 * zeroes), `account` will be queried for support of it. * * `account` being the zero address is an alias for the caller's address. */ function getInterfaceImplementer(address account, bytes32 interfaceHash) external view returns (address); /** * @dev Returns the interface hash for an `interfaceName`, as defined in the * corresponding * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP]. */ function interfaceHash(string calldata interfaceName) external pure returns (bytes32); /** * @notice Updates the cache with whether the contract implements an ERC165 interface or not. * @param account Address of the contract for which to update the cache. * @param interfaceId ERC165 interface for which to update the cache. */ function updateERC165Cache(address account, bytes4 interfaceId) external; /** * @notice Checks whether a contract implements an ERC165 interface or not. * If the result is not cached a direct lookup on the contract address is performed. * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling * {updateERC165Cache} with the contract address. * @param account Address of the contract to check. * @param interfaceId ERC165 interface to check. * @return True if `account` implements `interfaceId`, false otherwise. */ function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool); /** * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache. * @param account Address of the contract to check. * @param interfaceId ERC165 interface to check. * @return True if `account` implements `interfaceId`, false otherwise. */ function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer); event ManagerChanged(address indexed account, address indexed newManager); }
pragma solidity ^0.6.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
pragma solidity ^0.6.0; /** * @dev Interface of the ERC777Token standard as defined in the EIP. * * This contract uses the * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let * token holders and recipients react to token movements by using setting implementers * for the associated interfaces in said registry. See {IERC1820Registry} and * {ERC1820Implementer}. */ interface IERC777 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() external view returns (string memory); /** * @dev Returns the smallest part of the token that is not divisible. This * means all token operations (creation, movement and destruction) must have * amounts that are a multiple of this number. * * For most token contracts, this value will equal 1. */ function granularity() external view returns (uint256); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by an account (`owner`). */ function balanceOf(address owner) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * If send or receive hooks are registered for the caller and `recipient`, * the corresponding functions will be called with `data` and empty * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. * * Emits a {Sent} event. * * Requirements * * - the caller must have at least `amount` tokens. * - `recipient` cannot be the zero address. * - if `recipient` is a contract, it must implement the {IERC777Recipient} * interface. */ function send(address recipient, uint256 amount, bytes calldata data) external; /** * @dev Destroys `amount` tokens from the caller's account, reducing the * total supply. * * If a send hook is registered for the caller, the corresponding function * will be called with `data` and empty `operatorData`. See {IERC777Sender}. * * Emits a {Burned} event. * * Requirements * * - the caller must have at least `amount` tokens. */ function burn(uint256 amount, bytes calldata data) external; /** * @dev Returns true if an account is an operator of `tokenHolder`. * Operators can send and burn tokens on behalf of their owners. All * accounts are their own operator. * * See {operatorSend} and {operatorBurn}. */ function isOperatorFor(address operator, address tokenHolder) external view returns (bool); /** * @dev Make an account an operator of the caller. * * See {isOperatorFor}. * * Emits an {AuthorizedOperator} event. * * Requirements * * - `operator` cannot be calling address. */ function authorizeOperator(address operator) external; /** * @dev Revoke an account's operator status for the caller. * * See {isOperatorFor} and {defaultOperators}. * * Emits a {RevokedOperator} event. * * Requirements * * - `operator` cannot be calling address. */ function revokeOperator(address operator) external; /** * @dev Returns the list of default operators. These accounts are operators * for all token holders, even if {authorizeOperator} was never called on * them. * * This list is immutable, but individual holders may revoke these via * {revokeOperator}, in which case {isOperatorFor} will return false. */ function defaultOperators() external view returns (address[] memory); /** * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must * be an operator of `sender`. * * If send or receive hooks are registered for `sender` and `recipient`, * the corresponding functions will be called with `data` and * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. * * Emits a {Sent} event. * * Requirements * * - `sender` cannot be the zero address. * - `sender` must have at least `amount` tokens. * - the caller must be an operator for `sender`. * - `recipient` cannot be the zero address. * - if `recipient` is a contract, it must implement the {IERC777Recipient} * interface. */ function operatorSend( address sender, address recipient, uint256 amount, bytes calldata data, bytes calldata operatorData ) external; /** * @dev Destroys `amount` tokens from `account`, reducing the total supply. * The caller must be an operator of `account`. * * If a send hook is registered for `account`, the corresponding function * will be called with `data` and `operatorData`. See {IERC777Sender}. * * Emits a {Burned} event. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. * - the caller must be an operator for `account`. */ function operatorBurn( address account, uint256 amount, bytes calldata data, bytes calldata operatorData ) external; event Sent( address indexed operator, address indexed from, address indexed to, uint256 amount, bytes data, bytes operatorData ); event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); event AuthorizedOperator(address indexed operator, address indexed tokenHolder); event RevokedOperator(address indexed operator, address indexed tokenHolder); }
pragma solidity ^0.6.0; /** * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP. * * Accounts can be notified of {IERC777} tokens being sent to them by having a * contract implement this interface (contract holders can be their own * implementer) and registering it on the * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. * * See {IERC1820Registry} and {ERC1820Implementer}. */ interface IERC777Recipient { /** * @dev Called by an {IERC777} token contract whenever tokens are being * moved or created into a registered account (`to`). The type of operation * is conveyed by `from` being the zero address or not. * * This call occurs _after_ the token contract's state is updated, so * {IERC777-balanceOf}, etc., can be used to query the post-operation state. * * This function may revert to prevent the operation from being executed. */ function tokensReceived( address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external; }
// SPDX-License-Identifier: AGPL-3.0-only /* ILocker.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; /** * @dev Interface of Locker functions of the {TokenState} contract. * * The SKALE Network has three types of locked tokens: * * - Tokens that are transferrable but are currently locked into delegation with * a validator. See {DelegationController}; * * - Tokens that are not transferable from one address to another, but may be * delegated to a validator {getAndUpdateLockedAmount}. This lock enforces * Proof-of-Use requirements. See {TokenLaunchLocker}; and, * * - Tokens that are neither transferable nor delegatable * {getAndUpdateForbiddenForDelegationAmount}. This lock enforces slashing. * See {Punisher}. */ interface ILocker { /** * @dev Returns the locked amount of untransferable tokens of a given `wallet` */ function getAndUpdateLockedAmount(address wallet) external returns (uint); /** * @dev Returns the locked amount of untransferable and un-delegatable tokens of a given `wallet`. */ function getAndUpdateForbiddenForDelegationAmount(address wallet) external returns (uint); }
// SPDX-License-Identifier: AGPL-3.0-only /* IMintableToken.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; interface IMintableToken { function mint( address account, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external returns (bool); }
pragma solidity >=0.4.24 <0.7.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; }
// SPDX-License-Identifier: AGPL-3.0-only /* ISkaleDKG.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; interface ISkaleDKG { function openChannel(bytes32 schainId) external; function deleteChannel(bytes32 schainId) external; function isLastDKGSuccesful(bytes32 groupIndex) external view returns (bool); function isChannelOpened(bytes32 schainId) external view returns (bool); }
// SPDX-License-Identifier: AGPL-3.0-only /* KeyStorage.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./Decryption.sol"; import "./Permissions.sol"; import "./SchainsInternal.sol"; import "./ECDH.sol"; import "./Precompiled.sol"; import "./FieldOperations.sol"; contract KeyStorage is Permissions { using Fp2Operations for Fp2Operations.Fp2Point; using G2Operations for G2Operations.G2Point; struct BroadcastedData { KeyShare[] secretKeyContribution; G2Operations.G2Point[] verificationVector; } struct KeyShare { bytes32[2] publicKey; bytes32 share; } // Unused variable!! mapping(bytes32 => mapping(uint => BroadcastedData)) private _data; // mapping(bytes32 => G2Operations.G2Point) private _publicKeysInProgress; mapping(bytes32 => G2Operations.G2Point) private _schainsPublicKeys; // Unused variable mapping(bytes32 => G2Operations.G2Point[]) private _schainsNodesPublicKeys; // mapping(bytes32 => G2Operations.G2Point[]) private _previousSchainsPublicKeys; function deleteKey(bytes32 groupIndex) external allow("SkaleDKG") { _previousSchainsPublicKeys[groupIndex].push(_schainsPublicKeys[groupIndex]); delete _schainsPublicKeys[groupIndex]; } function initPublicKeyInProgress(bytes32 groupIndex) external allow("SkaleDKG") { _publicKeysInProgress[groupIndex] = G2Operations.getG2Zero(); } function adding(bytes32 groupIndex, G2Operations.G2Point memory value) external allow("SkaleDKG") { require(value.isG2(), "Incorrect g2 point"); _publicKeysInProgress[groupIndex] = value.addG2(_publicKeysInProgress[groupIndex]); } function finalizePublicKey(bytes32 groupIndex) external allow("SkaleDKG") { if (!_isSchainsPublicKeyZero(groupIndex)) { _previousSchainsPublicKeys[groupIndex].push(_schainsPublicKeys[groupIndex]); } _schainsPublicKeys[groupIndex] = _publicKeysInProgress[groupIndex]; delete _publicKeysInProgress[groupIndex]; } function getCommonPublicKey(bytes32 groupIndex) external view returns (G2Operations.G2Point memory) { return _schainsPublicKeys[groupIndex]; } function getPreviousPublicKey(bytes32 groupIndex) external view returns (G2Operations.G2Point memory) { uint length = _previousSchainsPublicKeys[groupIndex].length; if (length == 0) { return G2Operations.getG2Zero(); } return _previousSchainsPublicKeys[groupIndex][length - 1]; } function getAllPreviousPublicKeys(bytes32 groupIndex) external view returns (G2Operations.G2Point[] memory) { return _previousSchainsPublicKeys[groupIndex]; } function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); } function _isSchainsPublicKeyZero(bytes32 schainId) private view returns (bool) { return _schainsPublicKeys[schainId].x.a == 0 && _schainsPublicKeys[schainId].x.b == 0 && _schainsPublicKeys[schainId].y.a == 0 && _schainsPublicKeys[schainId].y.b == 0; } function _getData() private view returns (BroadcastedData memory) { return _data[keccak256(abi.encodePacked("UnusedFunction"))][0]; } function _getNodesPublicKey() private view returns (G2Operations.G2Point memory) { return _schainsNodesPublicKeys[keccak256(abi.encodePacked("UnusedFunction"))][0]; } }
// SPDX-License-Identifier: AGPL-3.0-only /* StringUtils.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; library MathUtils { event UnderflowError( uint a, uint b ); uint constant private _EPS = 1e6; function boundedSub(uint256 a, uint256 b) internal returns (uint256) { if (a >= b) { return a - b; } else { emit UnderflowError(a, b); return 0; } } function boundedSubWithoutEvent(uint256 a, uint256 b) internal pure returns (uint256) { if (a >= b) { return a - b; } else { return 0; } } function muchGreater(uint256 a, uint256 b) internal pure returns (bool) { assert(uint(-1) - _EPS > b); return a > b + _EPS; } function approximatelyEqual(uint256 a, uint256 b) internal pure returns (bool) { if (a > b) { return a - b < _EPS; } else { return b - a < _EPS; } } }
// SPDX-License-Identifier: AGPL-3.0-only /* Monitors.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./SafeCast.sol"; import "./ConstantsHolder.sol"; import "./Nodes.sol"; contract Monitors is Permissions { using StringUtils for string; using SafeCast for uint; struct Verdict { uint toNodeIndex; uint32 downtime; uint32 latency; } struct CheckedNode { uint nodeIndex; uint time; } struct CheckedNodeWithIp { uint nodeIndex; uint time; bytes4 ip; } mapping (bytes32 => CheckedNode[]) public checkedNodes; mapping (bytes32 => uint[][]) public verdicts; mapping (bytes32 => uint[]) public groupsForMonitors; mapping (bytes32 => uint) public lastVerdictBlocks; mapping (bytes32 => uint) public lastBountyBlocks; event MonitorCreated( uint nodeIndex, bytes32 monitorIndex, uint numberOfMonitors, uint[] nodesInGroup, uint time, uint gasSpend ); event VerdictWasSent( uint indexed fromMonitorIndex, uint indexed toNodeIndex, uint32 downtime, uint32 latency, bool status, uint previousBlockEvent, uint time, uint gasSpend ); event MetricsWereCalculated( uint forNodeIndex, uint32 averageDowntime, uint32 averageLatency, uint time, uint gasSpend ); event PeriodsWereSet( uint rewardPeriod, uint deltaPeriod, uint time, uint gasSpend ); event MonitorRotated( bytes32 monitorIndex, uint newNode ); /** * addMonitor - setup monitors of node */ function addMonitor(uint nodeIndex) external allow("SkaleManager") { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); bytes32 monitorIndex = keccak256(abi.encodePacked(nodeIndex)); _generateGroup(monitorIndex, nodeIndex, constantsHolder.NUMBER_OF_MONITORS()); CheckedNode memory checkedNode = _getCheckedNodeData(nodeIndex); for (uint i = 0; i < groupsForMonitors[monitorIndex].length; i++) { bytes32 index = keccak256(abi.encodePacked(groupsForMonitors[monitorIndex][i])); addCheckedNode(index, checkedNode); } emit MonitorCreated( nodeIndex, monitorIndex, groupsForMonitors[monitorIndex].length, groupsForMonitors[monitorIndex], block.timestamp, gasleft() ); } function deleteMonitor(uint nodeIndex) external allow("SkaleManager") { bytes32 monitorIndex = keccak256(abi.encodePacked(nodeIndex)); while (verdicts[keccak256(abi.encodePacked(nodeIndex))].length > 0) { verdicts[keccak256(abi.encodePacked(nodeIndex))].pop(); } uint[] memory nodesInGroup = groupsForMonitors[monitorIndex]; uint index; bytes32 monitoringIndex; for (uint i = 0; i < nodesInGroup.length; i++) { monitoringIndex = keccak256(abi.encodePacked(nodesInGroup[i])); (index, ) = _find(monitoringIndex, nodeIndex); if (index < checkedNodes[monitoringIndex].length) { if (index != checkedNodes[monitoringIndex].length.sub(1)) { checkedNodes[monitoringIndex][index] = checkedNodes[monitoringIndex][checkedNodes[monitoringIndex].length.sub(1)]; } checkedNodes[monitoringIndex].pop(); } } delete groupsForMonitors[monitorIndex]; } function removeCheckedNodes(uint nodeIndex) external allow("SkaleManager") { bytes32 monitorIndex = keccak256(abi.encodePacked(nodeIndex)); delete checkedNodes[monitorIndex]; } function sendVerdict(uint fromMonitorIndex, Verdict calldata verdict) external allow("SkaleManager") { uint index; uint time; bytes32 monitorIndex = keccak256(abi.encodePacked(fromMonitorIndex)); (index, time) = _find(monitorIndex, verdict.toNodeIndex); require(time > 0, "Checked Node does not exist in MonitorsArray"); if (time <= block.timestamp) { if (index != checkedNodes[monitorIndex].length.sub(1)) { checkedNodes[monitorIndex][index] = checkedNodes[monitorIndex][checkedNodes[monitorIndex].length.sub(1)]; } delete checkedNodes[monitorIndex][checkedNodes[monitorIndex].length.sub(1)]; checkedNodes[monitorIndex].pop(); ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); bool receiveVerdict = time.add(constantsHolder.deltaPeriod()) > block.timestamp; if (receiveVerdict) { verdicts[keccak256(abi.encodePacked(verdict.toNodeIndex))].push( [uint(verdict.downtime), uint(verdict.latency)] ); } _emitVerdictsEvent(fromMonitorIndex, verdict, receiveVerdict); } } function calculateMetrics(uint nodeIndex) external allow("SkaleManager") returns (uint averageDowntime, uint averageLatency) { bytes32 monitorIndex = keccak256(abi.encodePacked(nodeIndex)); uint lengthOfArray = getLengthOfMetrics(monitorIndex); uint[] memory downtimeArray = new uint[](lengthOfArray); uint[] memory latencyArray = new uint[](lengthOfArray); for (uint i = 0; i < lengthOfArray; i++) { downtimeArray[i] = verdicts[monitorIndex][i][0]; latencyArray[i] = verdicts[monitorIndex][i][1]; } if (lengthOfArray > 0) { averageDowntime = _median(downtimeArray); averageLatency = _median(latencyArray); } delete verdicts[monitorIndex]; } function setLastBountyBlock(uint nodeIndex) external allow("SkaleManager") { lastBountyBlocks[keccak256(abi.encodePacked(nodeIndex))] = block.number; } function getCheckedArray(bytes32 monitorIndex) external view returns (CheckedNodeWithIp[] memory checkedNodesWithIp) { Nodes nodes = Nodes(contractManager.getContract("Nodes")); checkedNodesWithIp = new CheckedNodeWithIp[](checkedNodes[monitorIndex].length); for (uint i = 0; i < checkedNodes[monitorIndex].length; ++i) { checkedNodesWithIp[i].nodeIndex = checkedNodes[monitorIndex][i].nodeIndex; checkedNodesWithIp[i].time = checkedNodes[monitorIndex][i].time; checkedNodesWithIp[i].ip = nodes.getNodeIP(checkedNodes[monitorIndex][i].nodeIndex); } } function getLastBountyBlock(uint nodeIndex) external view returns (uint) { return lastBountyBlocks[keccak256(abi.encodePacked(nodeIndex))]; } function getNodesInGroup(bytes32 monitorIndex) external view returns (uint[] memory) { return groupsForMonitors[monitorIndex]; } function getNumberOfNodesInGroup(bytes32 monitorIndex) external view returns (uint) { return groupsForMonitors[monitorIndex].length; } function initialize(address newContractsAddress) public override initializer { Permissions.initialize(newContractsAddress); } /** * Add checked node or update existing one if it is already exits */ function addCheckedNode(bytes32 monitorIndex, CheckedNode memory checkedNode) public allow("SkaleManager") { for (uint i = 0; i < checkedNodes[monitorIndex].length; ++i) { if (checkedNodes[monitorIndex][i].nodeIndex == checkedNode.nodeIndex) { checkedNodes[monitorIndex][i] = checkedNode; return; } } checkedNodes[monitorIndex].push(checkedNode); } function getLastReceivedVerdictBlock(uint nodeIndex) public view returns (uint) { return lastVerdictBlocks[keccak256(abi.encodePacked(nodeIndex))]; } function getLengthOfMetrics(bytes32 monitorIndex) public view returns (uint) { return verdicts[monitorIndex].length; } function _generateGroup(bytes32 monitorIndex, uint nodeIndex, uint numberOfNodes) private { Nodes nodes = Nodes(contractManager.getContract("Nodes")); uint[] memory activeNodes = nodes.getActiveNodeIds(); uint numberOfNodesInGroup; uint availableAmount = activeNodes.length.sub((nodes.isNodeActive(nodeIndex)) ? 1 : 0); if (numberOfNodes > availableAmount) { numberOfNodesInGroup = availableAmount; } else { numberOfNodesInGroup = numberOfNodes; } uint ignoringTail = 0; uint random = uint(keccak256(abi.encodePacked(uint(blockhash(block.number.sub(1))), monitorIndex))); for (uint i = 0; i < numberOfNodesInGroup; ++i) { uint index = random % (activeNodes.length.sub(ignoringTail)); if (activeNodes[index] == nodeIndex) { _swap(activeNodes, index, activeNodes.length.sub(ignoringTail).sub(1)); ++ignoringTail; index = random % (activeNodes.length.sub(ignoringTail)); } groupsForMonitors[monitorIndex].push(activeNodes[index]); _swap(activeNodes, index, activeNodes.length.sub(ignoringTail).sub(1)); ++ignoringTail; } } function _median(uint[] memory values) private pure returns (uint) { if (values.length < 1) { revert("Can't calculate _median of empty array"); } _quickSort(values, 0, values.length.sub(1)); return values[values.length.div(2)]; } function _swap(uint[] memory array, uint index1, uint index2) private pure { uint buffer = array[index1]; array[index1] = array[index2]; array[index2] = buffer; } function _find(bytes32 monitorIndex, uint nodeIndex) private view returns (uint index, uint time) { index = checkedNodes[monitorIndex].length; time = 0; for (uint i = 0; i < checkedNodes[monitorIndex].length; i++) { uint checkedNodeNodeIndex; uint checkedNodeTime; checkedNodeNodeIndex = checkedNodes[monitorIndex][i].nodeIndex; checkedNodeTime = checkedNodes[monitorIndex][i].time; if (checkedNodeNodeIndex == nodeIndex && (time == 0 || checkedNodeTime < time)) { index = i; time = checkedNodeTime; } } } function _quickSort(uint[] memory array, uint left, uint right) private pure { uint leftIndex = left; uint rightIndex = right; uint middle = array[right.add(left).div(2)]; while (leftIndex <= rightIndex) { while (array[leftIndex] < middle) { leftIndex++; } while (middle < array[rightIndex]) { rightIndex--; } if (leftIndex <= rightIndex) { (array[leftIndex], array[rightIndex]) = (array[rightIndex], array[leftIndex]); leftIndex++; rightIndex = (rightIndex > 0 ? rightIndex.sub(1) : 0); } } if (left < rightIndex) _quickSort(array, left, rightIndex); if (leftIndex < right) _quickSort(array, leftIndex, right); } function _getCheckedNodeData(uint nodeIndex) private view returns (CheckedNode memory checkedNode) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); Nodes nodes = Nodes(contractManager.getContract("Nodes")); checkedNode.nodeIndex = nodeIndex; checkedNode.time = nodes.getNodeNextRewardDate(nodeIndex).sub(constantsHolder.deltaPeriod()); } function _emitVerdictsEvent( uint fromMonitorIndex, Verdict memory verdict, bool receiveVerdict ) private { uint previousBlockEvent = getLastReceivedVerdictBlock(verdict.toNodeIndex); lastVerdictBlocks[keccak256(abi.encodePacked(verdict.toNodeIndex))] = block.number; emit VerdictWasSent( fromMonitorIndex, verdict.toNodeIndex, verdict.downtime, verdict.latency, receiveVerdict, previousBlockEvent, block.timestamp, gasleft() ); } }
// SPDX-License-Identifier: AGPL-3.0-only /* NodeRotation.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Vadim Yavorsky SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./Permissions.sol"; import "./ConstantsHolder.sol"; import "./SchainsInternal.sol"; import "./Schains.sol"; import "./Nodes.sol"; import "./ISkaleDKG.sol"; contract NodeRotation is Permissions { using StringUtils for string; using StringUtils for uint; /** * nodeIndex - index of Node which is in process of rotation(left from schain) * newNodeIndex - index of Node which is rotated(added to schain) * freezeUntil - time till which Node should be turned on * rotationCounter - how many rotations were on this schain */ struct Rotation { uint nodeIndex; uint newNodeIndex; uint freezeUntil; uint rotationCounter; } struct LeavingHistory { bytes32 schainIndex; uint finishedRotation; } mapping (bytes32 => Rotation) public rotations; mapping (uint => LeavingHistory[]) public leavingHistory; mapping (bytes32 => bool) public waitForNewNode; function exitFromSchain(uint nodeIndex) external allow("SkaleManager") returns (bool) { SchainsInternal schainsInternal = SchainsInternal(contractManager.getContract("SchainsInternal")); bytes32 schainId = schainsInternal.getActiveSchain(nodeIndex); require(_checkRotation(schainId), "No any free Nodes for rotating"); rotateNode(nodeIndex, schainId, true); return schainsInternal.getActiveSchain(nodeIndex) == bytes32(0) ? true : false; } function freezeSchains(uint nodeIndex) external allow("SkaleManager") { SchainsInternal schainsInternal = SchainsInternal(contractManager.getContract("SchainsInternal")); bytes32[] memory schains = schainsInternal.getActiveSchains(nodeIndex); for (uint i = 0; i < schains.length; i++) { Rotation memory rotation = rotations[schains[i]]; if (rotation.nodeIndex == nodeIndex && now < rotation.freezeUntil) { continue; } string memory schainName = schainsInternal.getSchainName(schains[i]); string memory revertMessage = "Node cannot rotate on Schain "; revertMessage = revertMessage.strConcat(schainName); revertMessage = revertMessage.strConcat(", occupied by Node "); revertMessage = revertMessage.strConcat(rotation.nodeIndex.uint2str()); string memory dkgRevert = "DKG proccess did not finish on schain "; ISkaleDKG skaleDKG = ISkaleDKG(contractManager.getContract("SkaleDKG")); require( skaleDKG.isLastDKGSuccesful(keccak256(abi.encodePacked(schainName))), dkgRevert.strConcat(schainName)); require(rotation.freezeUntil < now, revertMessage); _startRotation(schains[i], nodeIndex); } } function removeRotation(bytes32 schainIndex) external allow("Schains") { delete rotations[schainIndex]; } function skipRotationDelay(bytes32 schainIndex) external onlyOwner { rotations[schainIndex].freezeUntil = now; } function getRotation(bytes32 schainIndex) external view returns (Rotation memory) { return rotations[schainIndex]; } function getLeavingHistory(uint nodeIndex) external view returns (LeavingHistory[] memory) { return leavingHistory[nodeIndex]; } function isRotationInProgress(bytes32 schainIndex) external view returns (bool) { return rotations[schainIndex].freezeUntil >= now && !waitForNewNode[schainIndex]; } function initialize(address newContractsAddress) public override initializer { Permissions.initialize(newContractsAddress); } function rotateNode( uint nodeIndex, bytes32 schainId, bool shouldDelay ) public allowTwo("SkaleDKG", "SkaleManager") returns (uint newNode) { SchainsInternal schainsInternal = SchainsInternal(contractManager.getContract("SchainsInternal")); Schains schains = Schains(contractManager.getContract("Schains")); schainsInternal.removeNodeFromSchain(nodeIndex, schainId); newNode = selectNodeToGroup(schainId); uint8 space = schainsInternal.getSchainsPartOfNode(schainId); schains.addSpace(nodeIndex, space); _finishRotation(schainId, nodeIndex, newNode, shouldDelay); } /** * @dev selectNodeToGroup - pseudo-randomly select new Node for Schain * @param schainId - hash of name of Schain * @return nodeIndex - global index of Node */ function selectNodeToGroup(bytes32 schainId) public allowThree("SkaleManager", "Schains", "SkaleDKG") returns (uint) { SchainsInternal schainsInternal = SchainsInternal(contractManager.getContract("SchainsInternal")); Nodes nodes = Nodes(contractManager.getContract("Nodes")); require(schainsInternal.isSchainActive(schainId), "Group is not active"); uint8 space = schainsInternal.getSchainsPartOfNode(schainId); uint[] memory possibleNodes = schainsInternal.isEnoughNodes(schainId); require(possibleNodes.length > 0, "No any free Nodes for rotation"); uint nodeIndex; uint random = uint(keccak256(abi.encodePacked(uint(blockhash(block.number - 1)), schainId))); do { uint index = random % possibleNodes.length; nodeIndex = possibleNodes[index]; random = uint(keccak256(abi.encodePacked(random, nodeIndex))); } while (schainsInternal.checkException(schainId, nodeIndex)); require(nodes.removeSpaceFromNode(nodeIndex, space), "Could not remove space from nodeIndex"); schainsInternal.addSchainForNode(nodeIndex, schainId); schainsInternal.setException(schainId, nodeIndex); schainsInternal.setNodeInGroup(schainId, nodeIndex); return nodeIndex; } function _startRotation(bytes32 schainIndex, uint nodeIndex) private { ConstantsHolder constants = ConstantsHolder(contractManager.getContract("ConstantsHolder")); rotations[schainIndex].nodeIndex = nodeIndex; rotations[schainIndex].newNodeIndex = nodeIndex; rotations[schainIndex].freezeUntil = now.add(constants.rotationDelay()); waitForNewNode[schainIndex] = true; } function _finishRotation( bytes32 schainIndex, uint nodeIndex, uint newNodeIndex, bool shouldDelay) private { ConstantsHolder constants = ConstantsHolder(contractManager.getContract("ConstantsHolder")); leavingHistory[nodeIndex].push( LeavingHistory(schainIndex, shouldDelay ? now.add(constants.rotationDelay()) : now) ); rotations[schainIndex].newNodeIndex = newNodeIndex; rotations[schainIndex].rotationCounter++; delete waitForNewNode[schainIndex]; ISkaleDKG(contractManager.getContract("SkaleDKG")).openChannel(schainIndex); } function _checkRotation(bytes32 schainId ) private view returns (bool) { SchainsInternal schainsInternal = SchainsInternal(contractManager.getContract("SchainsInternal")); require(schainsInternal.isSchainExist(schainId), "Schain does not exist for rotation"); return schainsInternal.isAnyFreeNode(schainId); } }
// SPDX-License-Identifier: AGPL-3.0-only /* Nodes.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./SafeCast.sol"; import "./Permissions.sol"; import "./ConstantsHolder.sol"; import "./ValidatorService.sol"; import "./DelegationController.sol"; /** * @title Nodes - contract contains all functionality logic to manage Nodes */ contract Nodes is Permissions { using SafeCast for uint; // All Nodes states enum NodeStatus {Active, Leaving, Left, In_Maintenance} struct Node { string name; bytes4 ip; bytes4 publicIP; uint16 port; bytes32[2] publicKey; uint startBlock; uint lastRewardDate; uint finishTime; NodeStatus status; uint validatorId; } // struct to note which Nodes and which number of Nodes owned by user struct CreatedNodes { mapping (uint => bool) isNodeExist; uint numberOfNodes; } struct SpaceManaging { uint8 freeSpace; uint indexInSpaceMap; } // TODO: move outside the contract struct NodeCreationParams { string name; bytes4 ip; bytes4 publicIp; uint16 port; bytes32[2] publicKey; uint16 nonce; } // array which contain all Nodes Node[] public nodes; SpaceManaging[] public spaceOfNodes; // mapping for checking which Nodes and which number of Nodes owned by user mapping (address => CreatedNodes) public nodeIndexes; // mapping for checking is IP address busy mapping (bytes4 => bool) public nodesIPCheck; // mapping for checking is Name busy mapping (bytes32 => bool) public nodesNameCheck; // mapping for indication from Name to Index mapping (bytes32 => uint) public nodesNameToIndex; // mapping for indication from space to Nodes mapping (uint8 => uint[]) public spaceToNodes; mapping (uint => uint[]) public validatorToNodeIndexes; uint public numberOfActiveNodes; uint public numberOfLeavingNodes; uint public numberOfLeftNodes; // informs that Node is created event NodeCreated( uint nodeIndex, address owner, string name, bytes4 ip, bytes4 publicIP, uint16 port, uint16 nonce, uint time, uint gasSpend ); // informs that node is fully finished quitting from the system event ExitCompleted( uint nodeIndex, uint time, uint gasSpend ); // informs that owner starts the procedure of quitting the Node from the system event ExitInited( uint nodeIndex, uint startLeavingPeriod, uint time, uint gasSpend ); modifier checkNodeExists(uint nodeIndex) { require(nodeIndex < nodes.length, "Node with such index does not exist"); _; } /** * @dev removeSpaceFromFractionalNode - occupies space from Fractional Node * function could be run only by Schains * @param nodeIndex - index of Node at array of Fractional Nodes * @param space - space which should be occupied */ function removeSpaceFromNode(uint nodeIndex, uint8 space) external checkNodeExists(nodeIndex) allowTwo("NodeRotation", "SchainsInternal") returns (bool) { if (spaceOfNodes[nodeIndex].freeSpace < space) { return false; } if (space > 0) { _moveNodeToNewSpaceMap( nodeIndex, uint(spaceOfNodes[nodeIndex].freeSpace).sub(space).toUint8() ); } return true; } /** * @dev adSpaceToFractionalNode - returns space to Fractional Node * function could be run only be Schains * @param nodeIndex - index of Node at array of Fractional Nodes * @param space - space which should be returned */ function addSpaceToNode(uint nodeIndex, uint8 space) external checkNodeExists(nodeIndex) allow("Schains") { if (space > 0) { _moveNodeToNewSpaceMap( nodeIndex, uint(spaceOfNodes[nodeIndex].freeSpace).add(space).toUint8() ); } } /** * @dev changeNodeLastRewardDate - changes Node's last reward date * function could be run only by SkaleManager * @param nodeIndex - index of Node */ function changeNodeLastRewardDate(uint nodeIndex) external checkNodeExists(nodeIndex) allow("SkaleManager") { nodes[nodeIndex].lastRewardDate = block.timestamp; } function changeNodeFinishTime(uint nodeIndex, uint time) external checkNodeExists(nodeIndex) allow("SkaleManager") { nodes[nodeIndex].finishTime = time; } /** * @dev createNode - creates new Node and add it to the Nodes contract * function could be only run by SkaleManager * @param from - owner of Node */ // * @return nodeIndex - index of Node function createNode(address from, NodeCreationParams calldata params) external allow("SkaleManager") // returns (uint nodeIndex) { // checks that Node has correct data require(params.ip != 0x0 && !nodesIPCheck[params.ip], "IP address is zero or is not available"); require(!nodesNameCheck[keccak256(abi.encodePacked(params.name))], "Name has already registered"); require(params.port > 0, "Port is zero"); uint validatorId = ValidatorService( contractManager.getContract("ValidatorService")).getValidatorIdByNodeAddress(from); // adds Node to Nodes contract uint nodeIndex = _addNode( from, params.name, params.ip, params.publicIp, params.port, params.publicKey, validatorId); emit NodeCreated( nodeIndex, from, params.name, params.ip, params.publicIp, params.port, params.nonce, block.timestamp, gasleft()); } /** * @dev initExit - initiate a procedure of quitting the system * function could be only run by SkaleManager * @param nodeIndex - index of Node * @return true - if everything OK */ function initExit(uint nodeIndex) external checkNodeExists(nodeIndex) allow("SkaleManager") returns (bool) { _setNodeLeaving(nodeIndex); emit ExitInited( nodeIndex, block.timestamp, block.timestamp, gasleft()); return true; } /** * @dev completeExit - finish a procedure of quitting the system * function could be run only by SkaleManager * @param nodeIndex - index of Node * @return amount of SKL which be returned */ function completeExit(uint nodeIndex) external checkNodeExists(nodeIndex) allow("SkaleManager") returns (bool) { require(isNodeLeaving(nodeIndex), "Node is not Leaving"); _setNodeLeft(nodeIndex); _deleteNode(nodeIndex); emit ExitCompleted( nodeIndex, block.timestamp, gasleft()); return true; } function deleteNodeForValidator(uint validatorId, uint nodeIndex) external checkNodeExists(nodeIndex) allow("SkaleManager") { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); require(validatorService.validatorExists(validatorId), "Validator with such ID does not exist"); uint[] memory validatorNodes = validatorToNodeIndexes[validatorId]; uint position = _findNode(validatorNodes, nodeIndex); if (position < validatorNodes.length) { validatorToNodeIndexes[validatorId][position] = validatorToNodeIndexes[validatorId][validatorNodes.length.sub(1)]; } validatorToNodeIndexes[validatorId].pop(); } function checkPossibilityCreatingNode(address nodeAddress) external allow("SkaleManager") { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController") ); uint validatorId = validatorService.getValidatorIdByNodeAddress(nodeAddress); require(validatorService.isAuthorizedValidator(validatorId), "Validator is not authorized to create a node"); uint[] memory validatorNodes = validatorToNodeIndexes[validatorId]; uint delegationsTotal = delegationController.getAndUpdateDelegatedToValidatorNow(validatorId); uint msr = ConstantsHolder(contractManager.getContract("ConstantsHolder")).msr(); require( validatorNodes.length.add(1).mul(msr) <= delegationsTotal, "Validator must meet the Minimum Staking Requirement"); } function checkPossibilityToMaintainNode( uint validatorId, uint nodeIndex ) external checkNodeExists(nodeIndex) allow("Bounty") returns (bool) { DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController") ); ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); require(validatorService.validatorExists(validatorId), "Validator with such ID does not exist"); uint[] memory validatorNodes = validatorToNodeIndexes[validatorId]; uint position = _findNode(validatorNodes, nodeIndex); require(position < validatorNodes.length, "Node does not exist for this Validator"); uint delegationsTotal = delegationController.getAndUpdateDelegatedToValidatorNow(validatorId); uint msr = ConstantsHolder(contractManager.getContract("ConstantsHolder")).msr(); return position.add(1).mul(msr) <= delegationsTotal; } function setNodeInMaintenance(uint nodeIndex) external { require(nodes[nodeIndex].status == NodeStatus.Active, "Node is not Active"); ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); uint validatorId = getValidatorId(nodeIndex); bool permitted = (_isOwner() || isNodeExist(msg.sender, nodeIndex)); if (!permitted) { permitted = validatorService.getValidatorId(msg.sender) == validatorId; } require(permitted, "Sender is not permitted to call this function"); nodes[nodeIndex].status = NodeStatus.In_Maintenance; } function removeNodeFromInMaintenance(uint nodeIndex) external { require(nodes[nodeIndex].status == NodeStatus.In_Maintenance, "Node is not In Maintence"); ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); uint validatorId = getValidatorId(nodeIndex); bool permitted = (_isOwner() || isNodeExist(msg.sender, nodeIndex)); if (!permitted) { permitted = validatorService.getValidatorId(msg.sender) == validatorId; } require(permitted, "Sender is not permitted to call this function"); nodes[nodeIndex].status = NodeStatus.Active; } function getNodesWithFreeSpace(uint8 freeSpace) external view returns (uint[] memory) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); uint[] memory nodesWithFreeSpace = new uint[](countNodesWithFreeSpace(freeSpace)); uint cursor = 0; uint totalSpace = constantsHolder.TOTAL_SPACE_ON_NODE(); for (uint8 i = freeSpace; i <= totalSpace; ++i) { for (uint j = 0; j < spaceToNodes[i].length; j++) { nodesWithFreeSpace[cursor] = spaceToNodes[i][j]; ++cursor; } } return nodesWithFreeSpace; } /** * @dev isTimeForReward - checks if time for reward has come * @param nodeIndex - index of Node * @return if time for reward has come - true, else - false */ function isTimeForReward(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (bool) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); return uint(nodes[nodeIndex].lastRewardDate).add(constantsHolder.rewardPeriod()) <= block.timestamp; } /** * @dev getNodeIP - get ip address of Node * @param nodeIndex - index of Node * @return ip address */ function getNodeIP(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (bytes4) { require(nodeIndex < nodes.length, "Node does not exist"); return nodes[nodeIndex].ip; } /** * @dev getNodePort - get Node's port * @param nodeIndex - index of Node * @return port */ function getNodePort(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (uint16) { return nodes[nodeIndex].port; } function getNodePublicKey(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (bytes32[2] memory) { return nodes[nodeIndex].publicKey; } function getNodeFinishTime(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (uint) { return nodes[nodeIndex].finishTime; } /** * @dev isNodeLeft - checks if Node status Left * @param nodeIndex - index of Node * @return if Node status Left - true, else - false */ function isNodeLeft(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (bool) { return nodes[nodeIndex].status == NodeStatus.Left; } function isNodeInMaintenance(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (bool) { return nodes[nodeIndex].status == NodeStatus.In_Maintenance; } /** * @dev getNodeLastRewardDate - get Node last reward date * @param nodeIndex - index of Node * @return Node last reward date */ function getNodeLastRewardDate(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (uint) { return nodes[nodeIndex].lastRewardDate; } /** * @dev getNodeNextRewardDate - get Node next reward date * @param nodeIndex - index of Node * @return Node next reward date */ function getNodeNextRewardDate(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (uint) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); return nodes[nodeIndex].lastRewardDate.add(constantsHolder.rewardPeriod()); } /** * @dev getNumberOfNodes - get number of Nodes * @return number of Nodes */ function getNumberOfNodes() external view returns (uint) { return nodes.length; } /** * @dev getNumberOfFullNodes - get number Online Nodes * @return number of active nodes plus number of leaving nodes */ function getNumberOnlineNodes() external view returns (uint) { return numberOfActiveNodes.add(numberOfLeavingNodes); } /** * @dev getActiveNodeIPs - get array of ips of Active Nodes * @return activeNodeIPs - array of ips of Active Nodes */ function getActiveNodeIPs() external view returns (bytes4[] memory activeNodeIPs) { activeNodeIPs = new bytes4[](numberOfActiveNodes); uint indexOfActiveNodeIPs = 0; for (uint indexOfNodes = 0; indexOfNodes < nodes.length; indexOfNodes++) { if (isNodeActive(indexOfNodes)) { activeNodeIPs[indexOfActiveNodeIPs] = nodes[indexOfNodes].ip; indexOfActiveNodeIPs++; } } } /** * @dev getActiveNodesByAddress - get array of indexes of Active Nodes, which were * created by msg.sender * @return activeNodesByAddress Array of indexes of Active Nodes, which were created by msg.sender */ function getActiveNodesByAddress() external view returns (uint[] memory activeNodesByAddress) { activeNodesByAddress = new uint[](nodeIndexes[msg.sender].numberOfNodes); uint indexOfActiveNodesByAddress = 0; for (uint indexOfNodes = 0; indexOfNodes < nodes.length; indexOfNodes++) { if (nodeIndexes[msg.sender].isNodeExist[indexOfNodes] && isNodeActive(indexOfNodes)) { activeNodesByAddress[indexOfActiveNodesByAddress] = indexOfNodes; indexOfActiveNodesByAddress++; } } } /** * @dev getActiveNodeIds - get array of indexes of Active Nodes * @return activeNodeIds - array of indexes of Active Nodes */ function getActiveNodeIds() external view returns (uint[] memory activeNodeIds) { activeNodeIds = new uint[](numberOfActiveNodes); uint indexOfActiveNodeIds = 0; for (uint indexOfNodes = 0; indexOfNodes < nodes.length; indexOfNodes++) { if (isNodeActive(indexOfNodes)) { activeNodeIds[indexOfActiveNodeIds] = indexOfNodes; indexOfActiveNodeIds++; } } } function getNodeStatus(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (NodeStatus) { return nodes[nodeIndex].status; } function getValidatorNodeIndexes(uint validatorId) external view returns (uint[] memory) { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); require(validatorService.validatorExists(validatorId), "Validator with such ID does not exist"); return validatorToNodeIndexes[validatorId]; } /** * @dev constructor in Permissions approach * @param contractsAddress needed in Permissions constructor */ function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); numberOfActiveNodes = 0; numberOfLeavingNodes = 0; numberOfLeftNodes = 0; } function getValidatorId(uint nodeIndex) public view checkNodeExists(nodeIndex) returns (uint) { return nodes[nodeIndex].validatorId; } /** * @dev isNodeExist - checks existence of Node at this address * @param from - account address * @param nodeIndex - index of Node * @return if exist - true, else - false */ function isNodeExist(address from, uint nodeIndex) public view checkNodeExists(nodeIndex) returns (bool) { return nodeIndexes[from].isNodeExist[nodeIndex]; } /** * @dev isNodeActive - checks if Node status Active * @param nodeIndex - index of Node * @return if Node status Active - true, else - false */ function isNodeActive(uint nodeIndex) public view checkNodeExists(nodeIndex) returns (bool) { return nodes[nodeIndex].status == NodeStatus.Active; } /** * @dev isNodeLeaving - checks if Node status Leaving * @param nodeIndex - index of Node * @return if Node status Leaving - true, else - false */ function isNodeLeaving(uint nodeIndex) public view checkNodeExists(nodeIndex) returns (bool) { return nodes[nodeIndex].status == NodeStatus.Leaving; } function countNodesWithFreeSpace(uint8 freeSpace) public view returns (uint count) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); count = 0; uint totalSpace = constantsHolder.TOTAL_SPACE_ON_NODE(); for (uint8 i = freeSpace; i <= totalSpace; ++i) { count = count.add(spaceToNodes[i].length); } } function _findNode(uint[] memory validatorNodeIndexes, uint nodeIndex) private pure returns (uint) { uint i; for (i = 0; i < validatorNodeIndexes.length; i++) { if (validatorNodeIndexes[i] == nodeIndex) { return i; } } return validatorNodeIndexes.length; } function _moveNodeToNewSpaceMap(uint nodeIndex, uint8 newSpace) private { uint8 previousSpace = spaceOfNodes[nodeIndex].freeSpace; uint indexInArray = spaceOfNodes[nodeIndex].indexInSpaceMap; if (indexInArray < spaceToNodes[previousSpace].length.sub(1)) { uint shiftedIndex = spaceToNodes[previousSpace][spaceToNodes[previousSpace].length.sub(1)]; spaceToNodes[previousSpace][indexInArray] = shiftedIndex; spaceOfNodes[shiftedIndex].indexInSpaceMap = indexInArray; spaceToNodes[previousSpace].pop(); } else { spaceToNodes[previousSpace].pop(); } spaceToNodes[newSpace].push(nodeIndex); spaceOfNodes[nodeIndex].freeSpace = newSpace; spaceOfNodes[nodeIndex].indexInSpaceMap = spaceToNodes[newSpace].length.sub(1); } /** * @dev _setNodeLeft - set Node Left * function could be run only by Nodes * @param nodeIndex - index of Node */ function _setNodeLeft(uint nodeIndex) private { nodesIPCheck[nodes[nodeIndex].ip] = false; nodesNameCheck[keccak256(abi.encodePacked(nodes[nodeIndex].name))] = false; delete nodesNameToIndex[keccak256(abi.encodePacked(nodes[nodeIndex].name))]; if (nodes[nodeIndex].status == NodeStatus.Active) { numberOfActiveNodes--; } else { numberOfLeavingNodes--; } nodes[nodeIndex].status = NodeStatus.Left; numberOfLeftNodes++; } /** * @dev _setNodeLeaving - set Node Leaving * function could be run only by Nodes * @param nodeIndex - index of Node */ function _setNodeLeaving(uint nodeIndex) private { nodes[nodeIndex].status = NodeStatus.Leaving; numberOfActiveNodes--; numberOfLeavingNodes++; } /** * @dev _addNode - adds Node to array * function could be run only by executor * @param from - owner of Node * @param name - Node name * @param ip - Node ip * @param publicIP - Node public ip * @param port - Node public port * @param publicKey - Ethereum public key * @return nodeIndex Index of Node */ function _addNode( address from, string memory name, bytes4 ip, bytes4 publicIP, uint16 port, bytes32[2] memory publicKey, uint validatorId ) private returns (uint nodeIndex) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); nodes.push(Node({ name: name, ip: ip, publicIP: publicIP, port: port, //owner: from, publicKey: publicKey, startBlock: block.number, lastRewardDate: block.timestamp, finishTime: 0, status: NodeStatus.Active, validatorId: validatorId })); nodeIndex = nodes.length.sub(1); validatorToNodeIndexes[validatorId].push(nodeIndex); bytes32 nodeId = keccak256(abi.encodePacked(name)); nodesIPCheck[ip] = true; nodesNameCheck[nodeId] = true; nodesNameToIndex[nodeId] = nodeIndex; nodeIndexes[from].isNodeExist[nodeIndex] = true; nodeIndexes[from].numberOfNodes++; spaceOfNodes.push(SpaceManaging({ freeSpace: constantsHolder.TOTAL_SPACE_ON_NODE(), indexInSpaceMap: spaceToNodes[constantsHolder.TOTAL_SPACE_ON_NODE()].length })); spaceToNodes[constantsHolder.TOTAL_SPACE_ON_NODE()].push(nodeIndex); numberOfActiveNodes++; } function _deleteNode(uint nodeIndex) private { uint8 space = spaceOfNodes[nodeIndex].freeSpace; uint indexInArray = spaceOfNodes[nodeIndex].indexInSpaceMap; if (indexInArray < spaceToNodes[space].length.sub(1)) { uint shiftedIndex = spaceToNodes[space][spaceToNodes[space].length.sub(1)]; spaceToNodes[space][indexInArray] = shiftedIndex; spaceOfNodes[shiftedIndex].indexInSpaceMap = indexInArray; spaceToNodes[space].pop(); } else { spaceToNodes[space].pop(); } delete spaceOfNodes[nodeIndex].freeSpace; delete spaceOfNodes[nodeIndex].indexInSpaceMap; } }
pragma solidity ^0.6.0; import "./Context.sol"; import "./Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract OwnableUpgradeSafe is Initializable, ContextUpgradeSafe { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[49] private __gap; }
// SPDX-License-Identifier: AGPL-3.0-only /* PartialDifferences.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./MathUtils.sol"; import "./FractionUtils.sol"; /** * @title Partial Differences Library * @dev This library contains functions to manage Partial Differences data * structure. Partial Differences is an array of value differences over time. * * For example: assuming an array [3, 6, 3, 1, 2], partial differences can * represent this array as [_, 3, -3, -2, 1]. * * This data structure allows adding values on an open interval with O(1) * complexity. * * For example: add +5 to [3, 6, 3, 1, 2] starting from the second element (3), * instead of performing [3, 6, 3+5, 1+5, 2+5] partial differences allows * performing [_, 3, -3+5, -2, 1]. The original array can be restored by * adding values from partial differences. */ library PartialDifferences { using SafeMath for uint; using MathUtils for uint; struct Sequence { // month => diff mapping (uint => uint) addDiff; // month => diff mapping (uint => uint) subtractDiff; // month => value mapping (uint => uint) value; uint firstUnprocessedMonth; uint lastChangedMonth; } struct Value { // month => diff mapping (uint => uint) addDiff; // month => diff mapping (uint => uint) subtractDiff; uint value; uint firstUnprocessedMonth; uint lastChangedMonth; } // functions for sequence function addToSequence(Sequence storage sequence, uint diff, uint month) internal { require(sequence.firstUnprocessedMonth <= month, "Cannot add to the past"); if (sequence.firstUnprocessedMonth == 0) { sequence.firstUnprocessedMonth = month; } sequence.addDiff[month] = sequence.addDiff[month].add(diff); if (sequence.lastChangedMonth != month) { sequence.lastChangedMonth = month; } } function subtractFromSequence(Sequence storage sequence, uint diff, uint month) internal { require(sequence.firstUnprocessedMonth <= month, "Cannot subtract from the past"); if (sequence.firstUnprocessedMonth == 0) { sequence.firstUnprocessedMonth = month; } sequence.subtractDiff[month] = sequence.subtractDiff[month].add(diff); if (sequence.lastChangedMonth != month) { sequence.lastChangedMonth = month; } } function getAndUpdateValueInSequence(Sequence storage sequence, uint month) internal returns (uint) { if (sequence.firstUnprocessedMonth == 0) { return 0; } if (sequence.firstUnprocessedMonth <= month) { for (uint i = sequence.firstUnprocessedMonth; i <= month; ++i) { uint nextValue = sequence.value[i.sub(1)].add(sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]); if (sequence.value[i] != nextValue) { sequence.value[i] = nextValue; } if (sequence.addDiff[i] > 0) { delete sequence.addDiff[i]; } if (sequence.subtractDiff[i] > 0) { delete sequence.subtractDiff[i]; } } sequence.firstUnprocessedMonth = month.add(1); } return sequence.value[month]; } function reduceSequence( Sequence storage sequence, FractionUtils.Fraction memory reducingCoefficient, uint month) internal { require(month.add(1) >= sequence.firstUnprocessedMonth, "Can't reduce value in the past"); require( reducingCoefficient.numerator <= reducingCoefficient.denominator, "Increasing of values is not implemented"); if (sequence.firstUnprocessedMonth == 0) { return; } uint value = getAndUpdateValueInSequence(sequence, month); if (value.approximatelyEqual(0)) { return; } sequence.value[month] = sequence.value[month] .mul(reducingCoefficient.numerator) .div(reducingCoefficient.denominator); for (uint i = month.add(1); i <= sequence.lastChangedMonth; ++i) { sequence.subtractDiff[i] = sequence.subtractDiff[i] .mul(reducingCoefficient.numerator) .div(reducingCoefficient.denominator); } } // functions for value function addToValue(Value storage sequence, uint diff, uint month) internal { require(sequence.firstUnprocessedMonth <= month, "Cannot add to the past"); if (sequence.firstUnprocessedMonth == 0) { sequence.firstUnprocessedMonth = month; sequence.lastChangedMonth = month; } if (month > sequence.lastChangedMonth) { sequence.lastChangedMonth = month; } if (month >= sequence.firstUnprocessedMonth) { sequence.addDiff[month] = sequence.addDiff[month].add(diff); } else { sequence.value = sequence.value.add(diff); } } function subtractFromValue(Value storage sequence, uint diff, uint month) internal { require(sequence.firstUnprocessedMonth <= month.add(1), "Cannot subtract from the past"); if (sequence.firstUnprocessedMonth == 0) { sequence.firstUnprocessedMonth = month; sequence.lastChangedMonth = month; } if (month > sequence.lastChangedMonth) { sequence.lastChangedMonth = month; } if (month >= sequence.firstUnprocessedMonth) { sequence.subtractDiff[month] = sequence.subtractDiff[month].add(diff); } else { sequence.value = sequence.value.boundedSub(diff); } } function getAndUpdateValue(Value storage sequence, uint month) internal returns (uint) { require( month.add(1) >= sequence.firstUnprocessedMonth, "Cannot calculate value in the past"); if (sequence.firstUnprocessedMonth == 0) { return 0; } if (sequence.firstUnprocessedMonth <= month) { for (uint i = sequence.firstUnprocessedMonth; i <= month; ++i) { uint newValue = sequence.value.add(sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]); if (sequence.value != newValue) { sequence.value = newValue; } if (sequence.addDiff[i] > 0) { delete sequence.addDiff[i]; } if (sequence.subtractDiff[i] > 0) { delete sequence.subtractDiff[i]; } } sequence.firstUnprocessedMonth = month.add(1); } return sequence.value; } function reduceValue( Value storage sequence, uint amount, uint month) internal returns (FractionUtils.Fraction memory) { require(month.add(1) >= sequence.firstUnprocessedMonth, "Cannot reduce value in the past"); if (sequence.firstUnprocessedMonth == 0) { return FractionUtils.createFraction(0); } uint value = getAndUpdateValue(sequence, month); if (value.approximatelyEqual(0)) { return FractionUtils.createFraction(0); } uint _amount = amount; if (value < amount) { _amount = value; } FractionUtils.Fraction memory reducingCoefficient = FractionUtils.createFraction(value.boundedSub(_amount), value); reduceValueByCoefficient(sequence, reducingCoefficient, month); return reducingCoefficient; } function reduceValueByCoefficient( Value storage sequence, FractionUtils.Fraction memory reducingCoefficient, uint month) internal { reduceValueByCoefficientAndUpdateSumIfNeeded( sequence, sequence, reducingCoefficient, month, false); } function reduceValueByCoefficientAndUpdateSum( Value storage sequence, Value storage sumSequence, FractionUtils.Fraction memory reducingCoefficient, uint month) internal { reduceValueByCoefficientAndUpdateSumIfNeeded( sequence, sumSequence, reducingCoefficient, month, true); } function reduceValueByCoefficientAndUpdateSumIfNeeded( Value storage sequence, Value storage sumSequence, FractionUtils.Fraction memory reducingCoefficient, uint month, bool hasSumSequence) internal { require(month.add(1) >= sequence.firstUnprocessedMonth, "Cannot reduce value in the past"); if (hasSumSequence) { require(month.add(1) >= sumSequence.firstUnprocessedMonth, "Cannot reduce value in the past"); } require( reducingCoefficient.numerator <= reducingCoefficient.denominator, "Increasing of values is not implemented"); if (sequence.firstUnprocessedMonth == 0) { return; } uint value = getAndUpdateValue(sequence, month); if (value.approximatelyEqual(0)) { return; } uint newValue = sequence.value.mul(reducingCoefficient.numerator).div(reducingCoefficient.denominator); if (hasSumSequence) { subtractFromValue(sumSequence, sequence.value.boundedSub(newValue), month); } sequence.value = newValue; for (uint i = month.add(1); i <= sequence.lastChangedMonth; ++i) { uint newDiff = sequence.subtractDiff[i] .mul(reducingCoefficient.numerator) .div(reducingCoefficient.denominator); if (hasSumSequence) { sumSequence.subtractDiff[i] = sumSequence.subtractDiff[i] .boundedSub(sequence.subtractDiff[i].boundedSub(newDiff)); } sequence.subtractDiff[i] = newDiff; } } function clear(Value storage sequence) internal { for (uint i = sequence.firstUnprocessedMonth; i <= sequence.lastChangedMonth; ++i) { if (sequence.addDiff[i] > 0) { delete sequence.addDiff[i]; } if (sequence.subtractDiff[i] > 0) { delete sequence.subtractDiff[i]; } } if (sequence.value > 0) { delete sequence.value; } if (sequence.firstUnprocessedMonth > 0) { delete sequence.firstUnprocessedMonth; } if (sequence.lastChangedMonth > 0) { delete sequence.lastChangedMonth; } } }
// SPDX-License-Identifier: AGPL-3.0-only /* Permissions.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./SafeMath.sol"; import "./AccessControl.sol"; import "./ContractManager.sol"; /** * @title Permissions - connected module for Upgradeable approach, knows ContractManager * @author Artem Payvin */ contract Permissions is AccessControlUpgradeSafe { using SafeMath for uint; using Address for address; ContractManager public contractManager; /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_isOwner(), "Caller is not the owner"); _; } modifier onlyAdmin() { require(_isAdmin(msg.sender), "Caller is not an admin"); _; } /** * @dev allow - throws if called by any account and contract other than the owner * or `contractName` contract * @param contractName - human readable name of contract */ modifier allow(string memory contractName) { require( contractManager.contracts(keccak256(abi.encodePacked(contractName))) == msg.sender || _isOwner(), "Message sender is invalid"); _; } modifier allowTwo(string memory contractName1, string memory contractName2) { require( contractManager.contracts(keccak256(abi.encodePacked(contractName1))) == msg.sender || contractManager.contracts(keccak256(abi.encodePacked(contractName2))) == msg.sender || _isOwner(), "Message sender is invalid"); _; } modifier allowThree(string memory contractName1, string memory contractName2, string memory contractName3) { require( contractManager.contracts(keccak256(abi.encodePacked(contractName1))) == msg.sender || contractManager.contracts(keccak256(abi.encodePacked(contractName2))) == msg.sender || contractManager.contracts(keccak256(abi.encodePacked(contractName3))) == msg.sender || _isOwner(), "Message sender is invalid"); _; } function initialize(address contractManagerAddress) public virtual initializer { AccessControlUpgradeSafe.__AccessControl_init(); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); _setContractManager(contractManagerAddress); } function _isOwner() internal view returns (bool) { return hasRole(DEFAULT_ADMIN_ROLE, msg.sender); } function _isAdmin(address account) internal view returns (bool) { address skaleManagerAddress = contractManager.contracts(keccak256(abi.encodePacked("SkaleManager"))); if (skaleManagerAddress != address(0)) { AccessControlUpgradeSafe skaleManager = AccessControlUpgradeSafe(skaleManagerAddress); return skaleManager.hasRole(keccak256("ADMIN_ROLE"), account) || _isOwner(); } else { return _isOwner(); } } function _setContractManager(address contractManagerAddress) private { require(contractManagerAddress != address(0), "ContractManager address is not set"); require(contractManagerAddress.isContract(), "Address is not contract"); contractManager = ContractManager(contractManagerAddress); } }
// SPDX-License-Identifier: AGPL-3.0-only /* Precompiled.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; library Precompiled { function bigModExp(uint base, uint power, uint modulus) internal view returns (uint) { uint[6] memory inputToBigModExp; inputToBigModExp[0] = 32; inputToBigModExp[1] = 32; inputToBigModExp[2] = 32; inputToBigModExp[3] = base; inputToBigModExp[4] = power; inputToBigModExp[5] = modulus; uint[1] memory out; bool success; // solhint-disable-next-line no-inline-assembly assembly { success := staticcall(not(0), 5, inputToBigModExp, mul(6, 0x20), out, 0x20) } require(success, "BigModExp failed"); return out[0]; } function bn256ScalarMul(uint x, uint y, uint k) internal view returns (uint , uint ) { uint[3] memory inputToMul; uint[2] memory output; inputToMul[0] = x; inputToMul[1] = y; inputToMul[2] = k; bool success; // solhint-disable-next-line no-inline-assembly assembly { success := staticcall(not(0), 7, inputToMul, 0x60, output, 0x40) } require(success, "Multiplication failed"); return (output[0], output[1]); } function bn256Pairing( uint x1, uint y1, uint a1, uint b1, uint c1, uint d1, uint x2, uint y2, uint a2, uint b2, uint c2, uint d2) internal view returns (bool) { bool success; uint[12] memory inputToPairing; inputToPairing[0] = x1; inputToPairing[1] = y1; inputToPairing[2] = a1; inputToPairing[3] = b1; inputToPairing[4] = c1; inputToPairing[5] = d1; inputToPairing[6] = x2; inputToPairing[7] = y2; inputToPairing[8] = a2; inputToPairing[9] = b2; inputToPairing[10] = c2; inputToPairing[11] = d2; uint[1] memory out; // solhint-disable-next-line no-inline-assembly assembly { success := staticcall(not(0), 8, inputToPairing, mul(12, 0x20), out, 0x20) } require(success, "Pairing check failed"); return out[0] != 0; } }
// SPDX-License-Identifier: AGPL-3.0-only /* Punisher.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./Permissions.sol"; import "./ILocker.sol"; import "./ValidatorService.sol"; import "./DelegationController.sol"; /** * @title Punisher * @dev This contract handles all slashing and forgiving operations. */ contract Punisher is Permissions, ILocker { /** * @dev Emitted when a slashing condition occurs. */ event Slash( uint validatorId, uint amount ); /** * @dev Emitted when a forgive condition occurs. */ event Forgive( address wallet, uint amount ); // holder => tokens mapping (address => uint) private _locked; /** * @dev Executes slashing on a validator and its delegations by an `amount` * of tokens. Currently, SkaleDKG is the only service allowed to execute * slashing. * * Emits a Slash event. * * @param validatorId uint validator to be slashed * @param amount uint slashed amount */ function slash(uint validatorId, uint amount) external allow("SkaleDKG") { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController")); require(validatorService.validatorExists(validatorId), "Validator does not exist"); delegationController.confiscate(validatorId, amount); emit Slash(validatorId, amount); } /** * @dev Allows the Owner to forgive a slashing condition. * * Emits a Forgive event. * * @param holder address of the slashed * @param amount uint amount to be forgiven */ function forgive(address holder, uint amount) external onlyAdmin { DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController")); require(!delegationController.hasUnprocessedSlashes(holder), "Not all slashes were calculated"); if (amount > _locked[holder]) { delete _locked[holder]; } else { _locked[holder] = _locked[holder].sub(amount); } emit Forgive(holder, amount); } /** * @dev See ILocker-getAndUpdateLockedAmount */ function getAndUpdateLockedAmount(address wallet) external override returns (uint) { return _getAndUpdateLockedAmount(wallet); } /** * @dev See ILocker-getAndUpdateForbiddenForDelegationAmount */ function getAndUpdateForbiddenForDelegationAmount(address wallet) external override returns (uint) { return _getAndUpdateLockedAmount(wallet); } function handleSlash(address holder, uint amount) external allow("DelegationController") { _locked[holder] = _locked[holder].add(amount); } function initialize(address contractManagerAddress) public override initializer { Permissions.initialize(contractManagerAddress); } // private function _getAndUpdateLockedAmount(address wallet) private returns (uint) { DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController")); delegationController.processAllSlashes(wallet); return _locked[wallet]; } }
pragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's uintXX casting operators with added overflow * checks. * * Downcasting from uint256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} to extend it to smaller types, by performing * all math on `uint256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { require(value < 2**255, "SafeCast: value doesn't fit in an int256"); return int256(value); } }
pragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot 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-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: AGPL-3.0-only /* Schains.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./Permissions.sol"; import "./SchainsInternal.sol"; import "./ConstantsHolder.sol"; import "./KeyStorage.sol"; import "./SkaleVerifier.sol"; import "./FieldOperations.sol"; import "./NodeRotation.sol"; import "./ISkaleDKG.sol"; /** * @title Schains - contract contains all functionality logic to manage Schains */ contract Schains is Permissions { using StringUtils for string; using StringUtils for uint; struct SchainParameters { uint lifetime; uint8 typeOfSchain; uint16 nonce; string name; } // informs that Schain is created event SchainCreated( string name, address owner, uint partOfNode, uint lifetime, uint numberOfNodes, uint deposit, uint16 nonce, bytes32 schainId, uint time, uint gasSpend ); event SchainDeleted( address owner, string name, bytes32 indexed schainId ); event NodeRotated( bytes32 schainId, uint oldNode, uint newNode ); event NodeAdded( bytes32 schainId, uint newNode ); // informs that Schain based on some Nodes event SchainNodes( string name, bytes32 schainId, uint[] nodesInGroup, uint time, uint gasSpend ); bytes32 public constant SCHAIN_CREATOR_ROLE = keccak256("SCHAIN_CREATOR_ROLE"); /** * @dev addSchain - create Schain in the system * function could be run only by executor * @param from - owner of Schain * @param deposit - received amoung of SKL * @param data - Schain's data */ function addSchain(address from, uint deposit, bytes calldata data) external allow("SkaleManager") { SchainParameters memory schainParameters = _fallbackSchainParametersDataConverter(data); ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); uint schainCreationTimeStamp = constantsHolder.schainCreationTimeStamp(); uint minSchainLifetime = constantsHolder.minimalSchainLifetime(); require(now >= schainCreationTimeStamp, "It is not a time for creating Schain"); require( schainParameters.lifetime >= minSchainLifetime, "Minimal schain lifetime should be satisfied" ); require( getSchainPrice(schainParameters.typeOfSchain, schainParameters.lifetime) <= deposit, "Not enough money to create Schain"); _addSchain(from, deposit, schainParameters); } function addSchainByFoundation( uint lifetime, uint8 typeOfSchain, uint16 nonce, string calldata name ) external { require(hasRole(SCHAIN_CREATOR_ROLE, msg.sender), "Sender is not authorized to create schian"); SchainParameters memory schainParameters = SchainParameters({ lifetime: lifetime, typeOfSchain: typeOfSchain, nonce: nonce, name: name }); _addSchain(msg.sender, 0, schainParameters); } /** * @dev deleteSchain - removes Schain from the system * function could be run only by executor * @param from - owner of Schain * @param name - Schain name */ function deleteSchain(address from, string calldata name) external allow("SkaleManager") { NodeRotation nodeRotation = NodeRotation(contractManager.getContract("NodeRotation")); SchainsInternal schainsInternal = SchainsInternal(contractManager.getContract("SchainsInternal")); bytes32 schainId = keccak256(abi.encodePacked(name)); require( schainsInternal.isOwnerAddress(from, schainId), "Message sender is not an owner of Schain" ); address nodesAddress = contractManager.getContract("Nodes"); // removes Schain from Nodes uint[] memory nodesInGroup = schainsInternal.getNodesInGroup(schainId); uint8 partOfNode = schainsInternal.getSchainsPartOfNode(schainId); for (uint i = 0; i < nodesInGroup.length; i++) { uint schainIndex = schainsInternal.findSchainAtSchainsForNode( nodesInGroup[i], schainId ); if (schainsInternal.checkHoleForSchain(schainId, i)) { continue; } require( schainIndex < schainsInternal.getLengthOfSchainsForNode(nodesInGroup[i]), "Some Node does not contain given Schain"); schainsInternal.removeNodeFromSchain(nodesInGroup[i], schainId); schainsInternal.removeNodeFromExceptions(schainId, nodesInGroup[i]); if (!Nodes(nodesAddress).isNodeLeft(nodesInGroup[i])) { this.addSpace(nodesInGroup[i], partOfNode); } } schainsInternal.deleteGroup(schainId); schainsInternal.removeSchain(schainId, from); schainsInternal.removeHolesForSchain(schainId); nodeRotation.removeRotation(schainId); emit SchainDeleted(from, name, schainId); } function deleteSchainByRoot(string calldata name) external allow("SkaleManager") { NodeRotation nodeRotation = NodeRotation(contractManager.getContract("NodeRotation")); bytes32 schainId = keccak256(abi.encodePacked(name)); SchainsInternal schainsInternal = SchainsInternal( contractManager.getContract("SchainsInternal")); require(schainsInternal.isSchainExist(schainId), "Schain does not exist"); // removes Schain from Nodes uint[] memory nodesInGroup = schainsInternal.getNodesInGroup(schainId); uint8 partOfNode = schainsInternal.getSchainsPartOfNode(schainId); for (uint i = 0; i < nodesInGroup.length; i++) { uint schainIndex = schainsInternal.findSchainAtSchainsForNode( nodesInGroup[i], schainId ); if (schainsInternal.checkHoleForSchain(schainId, i)) { continue; } require( schainIndex < schainsInternal.getLengthOfSchainsForNode(nodesInGroup[i]), "Some Node does not contain given Schain"); schainsInternal.removeNodeFromSchain(nodesInGroup[i], schainId); schainsInternal.removeNodeFromExceptions(schainId, nodesInGroup[i]); this.addSpace(nodesInGroup[i], partOfNode); } schainsInternal.deleteGroup(schainId); address from = schainsInternal.getSchainOwner(schainId); schainsInternal.removeSchain(schainId, from); schainsInternal.removeHolesForSchain(schainId); nodeRotation.removeRotation(schainId); emit SchainDeleted(from, name, schainId); } function restartSchainCreation(string calldata name) external allow("SkaleManager") { NodeRotation nodeRotation = NodeRotation(contractManager.getContract("NodeRotation")); bytes32 schainId = keccak256(abi.encodePacked(name)); ISkaleDKG skaleDKG = ISkaleDKG(contractManager.getContract("SkaleDKG")); require(!skaleDKG.isLastDKGSuccesful(schainId), "DKG success"); SchainsInternal schainsInternal = SchainsInternal( contractManager.getContract("SchainsInternal")); require(schainsInternal.isAnyFreeNode(schainId), "No any free Nodes for rotation"); uint newNodeIndex = nodeRotation.selectNodeToGroup(schainId); skaleDKG.openChannel(schainId); emit NodeAdded(schainId, newNodeIndex); } /** * @dev addSpace - return occupied space to Node * @param nodeIndex - index of Node at common array of Nodes * @param partOfNode - divisor of given type of Schain */ function addSpace(uint nodeIndex, uint8 partOfNode) external allowTwo("Schains", "NodeRotation") { Nodes nodes = Nodes(contractManager.getContract("Nodes")); nodes.addSpaceToNode(nodeIndex, partOfNode); } /** * @dev verifySignature - verify signature which create Group by Groups BLS master public key * @param signatureA - first part of BLS signature * @param signatureB - second part of BLS signature * @param hash - hashed message * @param counter - smallest sub from square * @param hashA - first part of hashed message * @param hashB - second part of hashed message * @param schainName - name of the Schain * @return true - if correct, false - if not */ function verifySchainSignature( uint signatureA, uint signatureB, bytes32 hash, uint counter, uint hashA, uint hashB, string calldata schainName ) external view returns (bool) { SkaleVerifier skaleVerifier = SkaleVerifier(contractManager.getContract("SkaleVerifier")); G2Operations.G2Point memory publicKey = KeyStorage( contractManager.getContract("KeyStorage") ).getCommonPublicKey( keccak256(abi.encodePacked(schainName)) ); return skaleVerifier.verify( Fp2Operations.Fp2Point({ a: signatureA, b: signatureB }), hash, counter, hashA, hashB, publicKey ); } function initialize(address newContractsAddress) public override initializer { Permissions.initialize(newContractsAddress); } /** * @dev getSchainPrice - returns current price for given Schain * @param typeOfSchain - type of Schain * @param lifetime - lifetime of Schain * @return current price for given Schain */ function getSchainPrice(uint typeOfSchain, uint lifetime) public view returns (uint) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); uint nodeDeposit = constantsHolder.NODE_DEPOSIT(); uint numberOfNodes; uint8 divisor; (numberOfNodes, divisor) = getNodesDataFromTypeOfSchain(typeOfSchain); if (divisor == 0) { return 1e18; } else { uint up = nodeDeposit.mul(numberOfNodes.mul(lifetime.mul(2))); uint down = uint( uint(constantsHolder.SMALL_DIVISOR()) .mul(uint(constantsHolder.SECONDS_TO_YEAR())) .div(divisor) ); return up.div(down); } } /** * @dev getNodesDataFromTypeOfSchain - returns number if Nodes * and part of Node which needed to this Schain * @param typeOfSchain - type of Schain * @return numberOfNodes - number of Nodes needed to this Schain * @return partOfNode - divisor of given type of Schain */ function getNodesDataFromTypeOfSchain(uint typeOfSchain) public view returns (uint numberOfNodes, uint8 partOfNode) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); numberOfNodes = constantsHolder.NUMBER_OF_NODES_FOR_SCHAIN(); if (typeOfSchain == 1) { partOfNode = constantsHolder.SMALL_DIVISOR() / constantsHolder.SMALL_DIVISOR(); } else if (typeOfSchain == 2) { partOfNode = constantsHolder.SMALL_DIVISOR() / constantsHolder.MEDIUM_DIVISOR(); } else if (typeOfSchain == 3) { partOfNode = constantsHolder.SMALL_DIVISOR() / constantsHolder.LARGE_DIVISOR(); } else if (typeOfSchain == 4) { partOfNode = 0; numberOfNodes = constantsHolder.NUMBER_OF_NODES_FOR_TEST_SCHAIN(); } else if (typeOfSchain == 5) { partOfNode = constantsHolder.SMALL_DIVISOR() / constantsHolder.MEDIUM_TEST_DIVISOR(); numberOfNodes = constantsHolder.NUMBER_OF_NODES_FOR_MEDIUM_TEST_SCHAIN(); } else { revert("Bad schain type"); } } function _initializeSchainInSchainsInternal( string memory name, address from, uint deposit, uint lifetime) private { address dataAddress = contractManager.getContract("SchainsInternal"); require(SchainsInternal(dataAddress).isSchainNameAvailable(name), "Schain name is not available"); // initialize Schain SchainsInternal(dataAddress).initializeSchain( name, from, lifetime, deposit); SchainsInternal(dataAddress).setSchainIndex(keccak256(abi.encodePacked(name)), from); } /** * @dev fallbackSchainParameterDataConverter - converts data from bytes to normal parameters * @param data - concatenated parameters * @return schainParameters Parsed lifetime, typeOfSchain, nonce and name */ function _fallbackSchainParametersDataConverter(bytes memory data) private pure returns (SchainParameters memory schainParameters) { (schainParameters.lifetime, schainParameters.typeOfSchain, schainParameters.nonce, schainParameters.name) = abi.decode(data, (uint, uint8, uint16, string)); } /** * @dev _createGroupForSchain - creates Group for Schain * @param schainName - name of Schain * @param schainId - hash by name of Schain * @param numberOfNodes - number of Nodes needed for this Schain * @param partOfNode - divisor of given type of Schain */ function _createGroupForSchain( string memory schainName, bytes32 schainId, uint numberOfNodes, uint8 partOfNode ) private { SchainsInternal schainsInternal = SchainsInternal(contractManager.getContract("SchainsInternal")); uint[] memory nodesInGroup = schainsInternal.createGroupForSchain(schainId, numberOfNodes, partOfNode); ISkaleDKG(contractManager.getContract("SkaleDKG")).openChannel(schainId); emit SchainNodes( schainName, schainId, nodesInGroup, block.timestamp, gasleft()); } /** * @dev _addSchain - create Schain in the system * function could be run only by executor * @param from - owner of Schain * @param deposit - received amoung of SKL * @param schainParameters - Schain's data */ function _addSchain(address from, uint deposit, SchainParameters memory schainParameters) private { uint numberOfNodes; uint8 partOfNode; require(schainParameters.typeOfSchain <= 5, "Invalid type of Schain"); //initialize Schain _initializeSchainInSchainsInternal( schainParameters.name, from, deposit, schainParameters.lifetime); // create a group for Schain (numberOfNodes, partOfNode) = getNodesDataFromTypeOfSchain(schainParameters.typeOfSchain); _createGroupForSchain( schainParameters.name, keccak256(abi.encodePacked(schainParameters.name)), numberOfNodes, partOfNode ); emit SchainCreated( schainParameters.name, from, partOfNode, schainParameters.lifetime, numberOfNodes, deposit, schainParameters.nonce, keccak256(abi.encodePacked(schainParameters.name)), block.timestamp, gasleft()); } }
// SPDX-License-Identifier: AGPL-3.0-only /* SchainsInternal.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./ConstantsHolder.sol"; import "./Nodes.sol"; import "./ISkaleDKG.sol"; /** * @title SchainsInternal - contract contains all functionality logic to manage Schains */ contract SchainsInternal is Permissions { struct Schain { string name; address owner; uint indexInOwnerList; uint8 partOfNode; uint lifetime; uint startDate; uint startBlock; uint deposit; uint64 index; } // mapping which contain all schains mapping (bytes32 => Schain) public schains; mapping (bytes32 => bool) public isSchainActive; mapping (bytes32 => uint[]) public schainsGroups; mapping (bytes32 => mapping (uint => bool)) private _exceptionsForGroups; // mapping shows schains by owner's address mapping (address => bytes32[]) public schainIndexes; // mapping shows schains which Node composed in mapping (uint => bytes32[]) public schainsForNodes; mapping (uint => uint[]) public holesForNodes; mapping (bytes32 => uint[]) public holesForSchains; // array which contain all schains bytes32[] public schainsAtSystem; uint64 public numberOfSchains; // total resources that schains occupied uint public sumOfSchainsResources; mapping (bytes32 => bool) public usedSchainNames; /** * @dev initializeSchain - initializes Schain * function could be run only by executor * @param name - SChain name * @param from - Schain owner * @param lifetime - initial lifetime of Schain * @param deposit - given amount of SKL */ function initializeSchain( string calldata name, address from, uint lifetime, uint deposit) external allow("Schains") { bytes32 schainId = keccak256(abi.encodePacked(name)); schains[schainId].name = name; schains[schainId].owner = from; schains[schainId].startDate = block.timestamp; schains[schainId].startBlock = block.number; schains[schainId].lifetime = lifetime; schains[schainId].deposit = deposit; schains[schainId].index = numberOfSchains; isSchainActive[schainId] = true; numberOfSchains++; schainsAtSystem.push(schainId); usedSchainNames[schainId] = true; } function createGroupForSchain( bytes32 schainId, uint numberOfNodes, uint8 partOfNode ) external allow("Schains") returns (uint[] memory) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); schains[schainId].partOfNode = partOfNode; if (partOfNode > 0) { sumOfSchainsResources = sumOfSchainsResources.add( numberOfNodes.mul(constantsHolder.TOTAL_SPACE_ON_NODE()).div(partOfNode) ); } return _generateGroup(schainId, numberOfNodes); } /** * @dev setSchainIndex - adds Schain's hash to owner * function could be run only by executor * @param schainId - hash by Schain name * @param from - Schain owner */ function setSchainIndex(bytes32 schainId, address from) external allow("Schains") { schains[schainId].indexInOwnerList = schainIndexes[from].length; schainIndexes[from].push(schainId); } /** * @dev changeLifetime - changes Lifetime for Schain * function could be run only by executor * @param schainId - hash by Schain name * @param lifetime - time which would be added to lifetime of Schain * @param deposit - amount of SKL which payed for this time */ function changeLifetime(bytes32 schainId, uint lifetime, uint deposit) external allow("Schains") { schains[schainId].deposit = schains[schainId].deposit.add(deposit); schains[schainId].lifetime = schains[schainId].lifetime.add(lifetime); } /** * @dev removeSchain - removes Schain from the system * function could be run only by executor * @param schainId - hash by Schain name * @param from - owner of Schain */ function removeSchain(bytes32 schainId, address from) external allow("Schains") { isSchainActive[schainId] = false; uint length = schainIndexes[from].length; uint index = schains[schainId].indexInOwnerList; if (index != length.sub(1)) { bytes32 lastSchainId = schainIndexes[from][length.sub(1)]; schains[lastSchainId].indexInOwnerList = index; schainIndexes[from][index] = lastSchainId; } schainIndexes[from].pop(); // TODO: // optimize for (uint i = 0; i + 1 < schainsAtSystem.length; i++) { if (schainsAtSystem[i] == schainId) { schainsAtSystem[i] = schainsAtSystem[schainsAtSystem.length.sub(1)]; break; } } schainsAtSystem.pop(); delete schains[schainId]; numberOfSchains--; } function removeNodeFromSchain( uint nodeIndex, bytes32 schainHash ) external allowThree("NodeRotation", "SkaleDKG", "Schains") { uint indexOfNode = _findNode(schainHash, nodeIndex); uint indexOfLastNode = schainsGroups[schainHash].length.sub(1); if (indexOfNode == indexOfLastNode) { schainsGroups[schainHash].pop(); } else { delete schainsGroups[schainHash][indexOfNode]; if (holesForSchains[schainHash].length > 0 && holesForSchains[schainHash][0] > indexOfNode) { uint hole = holesForSchains[schainHash][0]; holesForSchains[schainHash][0] = indexOfNode; holesForSchains[schainHash].push(hole); } else { holesForSchains[schainHash].push(indexOfNode); } } uint schainId = findSchainAtSchainsForNode(nodeIndex, schainHash); removeSchainForNode(nodeIndex, schainId); } function removeNodeFromExceptions(bytes32 schainHash, uint nodeIndex) external allow("Schains") { _exceptionsForGroups[schainHash][nodeIndex] = false; } /** * @dev deleteGroup - delete Group from Data contract * function could be run only by executor * @param schainId - Groups identifier */ function deleteGroup(bytes32 schainId) external allow("Schains") { // delete channel ISkaleDKG skaleDKG = ISkaleDKG(contractManager.getContract("SkaleDKG")); delete schainsGroups[schainId]; if (skaleDKG.isChannelOpened(schainId)) { skaleDKG.deleteChannel(schainId); } } /** * @dev setException - sets a Node like exception * function could be run only by executor * @param schainId - Groups identifier * @param nodeIndex - index of Node which would be notes like exception */ function setException(bytes32 schainId, uint nodeIndex) external allowTwo("Schains", "NodeRotation") { _exceptionsForGroups[schainId][nodeIndex] = true; } /** * @dev setNodeInGroup - adds Node to Group * function could be run only by executor * @param schainId - Groups * @param nodeIndex - index of Node which would be added to the Group */ function setNodeInGroup(bytes32 schainId, uint nodeIndex) external allowTwo("Schains", "NodeRotation") { if (holesForSchains[schainId].length == 0) { schainsGroups[schainId].push(nodeIndex); } else { schainsGroups[schainId][holesForSchains[schainId][0]] = nodeIndex; uint min = uint(-1); uint index = 0; for (uint i = 1; i < holesForSchains[schainId].length; i++) { if (min > holesForSchains[schainId][i]) { min = holesForSchains[schainId][i]; index = i; } } if (min == uint(-1)) { delete holesForSchains[schainId]; } else { holesForSchains[schainId][0] = min; holesForSchains[schainId][index] = holesForSchains[schainId][holesForSchains[schainId].length - 1]; holesForSchains[schainId].pop(); } } } function removeHolesForSchain(bytes32 schainHash) external allow("Schains") { delete holesForSchains[schainHash]; } /** * @dev getSchains - gets all Schains at the system * @return array of hashes by Schain names */ function getSchains() external view returns (bytes32[] memory) { return schainsAtSystem; } /** * @dev getSchainsPartOfNode - gets occupied space for given Schain * @param schainId - hash by Schain name * @return occupied space */ function getSchainsPartOfNode(bytes32 schainId) external view returns (uint8) { return schains[schainId].partOfNode; } /** * @dev getSchainListSize - gets number of created Schains at the system by owner * @param from - owner of Schain * return number of Schains */ function getSchainListSize(address from) external view returns (uint) { return schainIndexes[from].length; } /** * @dev getSchainIdsByAddress - gets array of hashes by Schain names which owned by `from` * @param from - owner of some Schains * @return array of hashes by Schain names */ function getSchainIdsByAddress(address from) external view returns (bytes32[] memory) { return schainIndexes[from]; } /** * @dev getSchainIdsForNode - returns array of hashes by Schain names, * which given Node composed * @param nodeIndex - index of Node * @return array of hashes by Schain names */ function getSchainIdsForNode(uint nodeIndex) external view returns (bytes32[] memory) { return schainsForNodes[nodeIndex]; } function getSchainOwner(bytes32 schainId) external view returns (address) { return schains[schainId].owner; } /** * @dev isSchainNameAvailable - checks is given name available * Need to delete - copy of web3.utils.soliditySha3 * @param name - possible new name of Schain * @return if available - true, else - false */ function isSchainNameAvailable(string calldata name) external view returns (bool) { bytes32 schainId = keccak256(abi.encodePacked(name)); return schains[schainId].owner == address(0) && !usedSchainNames[schainId]; } /** * @dev isTimeExpired - checks is Schain lifetime expired * @param schainId - hash by Schain name * @return if expired - true, else - false */ function isTimeExpired(bytes32 schainId) external view returns (bool) { return uint(schains[schainId].startDate).add(schains[schainId].lifetime) < block.timestamp; } /** * @dev isOwnerAddress - checks is `from` - owner of `schainId` Schain * @param from - owner of Schain * @param schainId - hash by Schain name * @return if owner - true, else - false */ function isOwnerAddress(address from, bytes32 schainId) external view returns (bool) { return schains[schainId].owner == from; } function isSchainExist(bytes32 schainId) external view returns (bool) { return keccak256(abi.encodePacked(schains[schainId].name)) != keccak256(abi.encodePacked("")); } function getSchainName(bytes32 schainId) external view returns (string memory) { return schains[schainId].name; } function getActiveSchain(uint nodeIndex) external view returns (bytes32) { for (uint i = schainsForNodes[nodeIndex].length; i > 0; i--) { if (schainsForNodes[nodeIndex][i - 1] != bytes32(0)) { return schainsForNodes[nodeIndex][i - 1]; } } return bytes32(0); } function getActiveSchains(uint nodeIndex) external view returns (bytes32[] memory activeSchains) { uint activeAmount = 0; for (uint i = 0; i < schainsForNodes[nodeIndex].length; i++) { if (schainsForNodes[nodeIndex][i] != bytes32(0)) { activeAmount++; } } uint cursor = 0; activeSchains = new bytes32[](activeAmount); for (uint i = schainsForNodes[nodeIndex].length; i > 0; i--) { if (schainsForNodes[nodeIndex][i - 1] != bytes32(0)) { activeSchains[cursor++] = schainsForNodes[nodeIndex][i - 1]; } } } /** * @dev getNumberOfNodesInGroup - shows number of Nodes in Group * @param schainId - Groups identifier * @return number of Nodes in Group */ function getNumberOfNodesInGroup(bytes32 schainId) external view returns (uint) { return schainsGroups[schainId].length; } /** * @dev getNodesInGroup - shows Nodes in Group * @param schainId - Groups identifier * @return array of indexes of Nodes in Group */ function getNodesInGroup(bytes32 schainId) external view returns (uint[] memory) { return schainsGroups[schainId]; } /** * @dev getNodeIndexInGroup - looks for Node in Group * @param schainId - Groups identifier * @param nodeId - Nodes identifier * @return index of Node in Group */ function getNodeIndexInGroup(bytes32 schainId, uint nodeId) external view returns (uint) { for (uint index = 0; index < schainsGroups[schainId].length; index++) { if (schainsGroups[schainId][index] == nodeId) { return index; } } return schainsGroups[schainId].length; } function isAnyFreeNode(bytes32 schainId) external view returns (bool) { Nodes nodes = Nodes(contractManager.getContract("Nodes")); uint8 space = schains[schainId].partOfNode; uint[] memory nodesWithFreeSpace = nodes.getNodesWithFreeSpace(space); for (uint i = 0; i < nodesWithFreeSpace.length; i++) { if (_isCorrespond(schainId, nodesWithFreeSpace[i])) { return true; } } return false; } function checkException(bytes32 schainId, uint nodeIndex) external view returns (bool) { return _exceptionsForGroups[schainId][nodeIndex]; } function checkHoleForSchain(bytes32 schainHash, uint indexOfNode) external view returns (bool) { for (uint i = 0; i < holesForSchains[schainHash].length; i++) { if (holesForSchains[schainHash][i] == indexOfNode) { return true; } } return false; } function initialize(address newContractsAddress) public override initializer { Permissions.initialize(newContractsAddress); numberOfSchains = 0; sumOfSchainsResources = 0; } /** * @dev addSchainForNode - adds Schain hash to Node * function could be run only by executor * @param nodeIndex - index of Node * @param schainId - hash by Schain name */ function addSchainForNode(uint nodeIndex, bytes32 schainId) public allowTwo("Schains", "NodeRotation") { if (holesForNodes[nodeIndex].length == 0) { schainsForNodes[nodeIndex].push(schainId); } else { schainsForNodes[nodeIndex][holesForNodes[nodeIndex][0]] = schainId; uint min = uint(-1); uint index = 0; for (uint i = 1; i < holesForNodes[nodeIndex].length; i++) { if (min > holesForNodes[nodeIndex][i]) { min = holesForNodes[nodeIndex][i]; index = i; } } if (min == uint(-1)) { delete holesForNodes[nodeIndex]; } else { holesForNodes[nodeIndex][0] = min; holesForNodes[nodeIndex][index] = holesForNodes[nodeIndex][holesForNodes[nodeIndex].length - 1]; holesForNodes[nodeIndex].pop(); } } } /** * @dev removesSchainForNode - clean given Node of Schain * function could be run only by executor * @param nodeIndex - index of Node * @param schainIndex - index of Schain in schainsForNodes array by this Node */ function removeSchainForNode(uint nodeIndex, uint schainIndex) public allowThree("NodeRotation", "SkaleDKG", "Schains") { uint length = schainsForNodes[nodeIndex].length; if (schainIndex == length.sub(1)) { schainsForNodes[nodeIndex].pop(); } else { schainsForNodes[nodeIndex][schainIndex] = bytes32(0); if (holesForNodes[nodeIndex].length > 0 && holesForNodes[nodeIndex][0] > schainIndex) { uint hole = holesForNodes[nodeIndex][0]; holesForNodes[nodeIndex][0] = schainIndex; holesForNodes[nodeIndex].push(hole); } else { holesForNodes[nodeIndex].push(schainIndex); } } } /** * @dev getLengthOfSchainsForNode - returns number of Schains which contain given Node * @param nodeIndex - index of Node * @return number of Schains */ function getLengthOfSchainsForNode(uint nodeIndex) public view returns (uint) { return schainsForNodes[nodeIndex].length; } /** * @dev findSchainAtSchainsForNode - finds index of Schain at schainsForNode array * @param nodeIndex - index of Node at common array of Nodes * @param schainId - hash of name of Schain * @return index of Schain at schainsForNode array */ function findSchainAtSchainsForNode(uint nodeIndex, bytes32 schainId) public view returns (uint) { uint length = getLengthOfSchainsForNode(nodeIndex); for (uint i = 0; i < length; i++) { if (schainsForNodes[nodeIndex][i] == schainId) { return i; } } return length; } function isEnoughNodes(bytes32 schainId) public view returns (uint[] memory result) { Nodes nodes = Nodes(contractManager.getContract("Nodes")); uint8 space = schains[schainId].partOfNode; uint[] memory nodesWithFreeSpace = nodes.getNodesWithFreeSpace(space); uint counter = 0; for (uint i = 0; i < nodesWithFreeSpace.length; i++) { if (!_isCorrespond(schainId, nodesWithFreeSpace[i])) { counter++; } } if (counter < nodesWithFreeSpace.length) { result = new uint[](nodesWithFreeSpace.length.sub(counter)); counter = 0; for (uint i = 0; i < nodesWithFreeSpace.length; i++) { if (_isCorrespond(schainId, nodesWithFreeSpace[i])) { result[counter] = nodesWithFreeSpace[i]; counter++; } } } } /** * @dev _generateGroup - generates Group for Schain * @param schainId - index of Group */ function _generateGroup(bytes32 schainId, uint numberOfNodes) private returns (uint[] memory nodesInGroup) { Nodes nodes = Nodes(contractManager.getContract("Nodes")); uint8 space = schains[schainId].partOfNode; nodesInGroup = new uint[](numberOfNodes); uint[] memory possibleNodes = isEnoughNodes(schainId); require(possibleNodes.length >= nodesInGroup.length, "Not enough nodes to create Schain"); uint ignoringTail = 0; uint random = uint(keccak256(abi.encodePacked(uint(blockhash(block.number.sub(1))), schainId))); for (uint i = 0; i < nodesInGroup.length; ++i) { uint index = random % (possibleNodes.length.sub(ignoringTail)); uint node = possibleNodes[index]; nodesInGroup[i] = node; _swap(possibleNodes, index, possibleNodes.length.sub(ignoringTail).sub(1)); ++ignoringTail; _exceptionsForGroups[schainId][node] = true; addSchainForNode(node, schainId); require(nodes.removeSpaceFromNode(node, space), "Could not remove space from Node"); } // set generated group schainsGroups[schainId] = nodesInGroup; } function _isCorrespond(bytes32 schainId, uint nodeIndex) private view returns (bool) { Nodes nodes = Nodes(contractManager.getContract("Nodes")); return !_exceptionsForGroups[schainId][nodeIndex] && nodes.isNodeActive(nodeIndex); } function _swap(uint[] memory array, uint index1, uint index2) private pure { uint buffer = array[index1]; array[index1] = array[index2]; array[index2] = buffer; } /** * @dev findNode - find local index of Node in Schain * @param schainId - Groups identifier * @param nodeIndex - global index of Node * @return local index of Node in Schain */ function _findNode(bytes32 schainId, uint nodeIndex) private view returns (uint) { uint[] memory nodesInGroup = schainsGroups[schainId]; uint index; for (index = 0; index < nodesInGroup.length; index++) { if (nodesInGroup[index] == nodeIndex) { return index; } } return index; } }
// SPDX-License-Identifier: AGPL-3.0-only /* SkaleManager.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./IERC1820Registry.sol"; import "./IERC777.sol"; import "./IERC777Recipient.sol"; import "./Distributor.sol"; import "./ValidatorService.sol"; import "./IMintableToken.sol"; import "./Bounty.sol"; import "./ConstantsHolder.sol"; import "./Monitors.sol"; import "./NodeRotation.sol"; import "./Permissions.sol"; import "./Schains.sol"; contract SkaleManager is IERC777Recipient, Permissions { IERC1820Registry private _erc1820; bytes32 constant private _TOKENS_RECIPIENT_INTERFACE_HASH = 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b; bytes32 constant public ADMIN_ROLE = keccak256("ADMIN_ROLE"); event BountyGot( uint indexed nodeIndex, address owner, uint averageDowntime, uint averageLatency, uint bounty, uint previousBlockEvent, uint time, uint gasSpend ); function tokensReceived( address, // operator address from, address to, uint256 value, bytes calldata userData, bytes calldata // operator data ) external override allow("SkaleToken") { require(to == address(this), "Receiver is incorrect"); if (userData.length > 0) { Schains schains = Schains( contractManager.getContract("Schains")); schains.addSchain(from, value, userData); } } function createNode( uint16 port, uint16 nonce, bytes4 ip, bytes4 publicIp, bytes32[2] calldata publicKey, string calldata name) external { Nodes nodes = Nodes(contractManager.getContract("Nodes")); // validators checks inside checkPossibilityCreatingNode nodes.checkPossibilityCreatingNode(msg.sender); Nodes.NodeCreationParams memory params = Nodes.NodeCreationParams({ name: name, ip: ip, publicIp: publicIp, port: port, publicKey: publicKey, nonce: nonce}); nodes.createNode(msg.sender, params); // uint nodeIndex = nodes.createNode(msg.sender, params); // Monitors monitors = Monitors(contractManager.getContract("Monitors")); // monitors.addMonitor(nodeIndex); } function nodeExit(uint nodeIndex) external { NodeRotation nodeRotation = NodeRotation(contractManager.getContract("NodeRotation")); ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); Nodes nodes = Nodes(contractManager.getContract("Nodes")); uint validatorId = nodes.getValidatorId(nodeIndex); bool permitted = (_isOwner() || nodes.isNodeExist(msg.sender, nodeIndex)); if (!permitted) { permitted = validatorService.getValidatorId(msg.sender) == validatorId; } require(permitted, "Sender is not permitted to call this function"); SchainsInternal schainsInternal = SchainsInternal(contractManager.getContract("SchainsInternal")); ConstantsHolder constants = ConstantsHolder(contractManager.getContract("ConstantsHolder")); nodeRotation.freezeSchains(nodeIndex); if (nodes.isNodeActive(nodeIndex)) { require(nodes.initExit(nodeIndex), "Initialization of node exit is failed"); } bool completed; bool isSchains = false; if (schainsInternal.getActiveSchain(nodeIndex) != bytes32(0)) { completed = nodeRotation.exitFromSchain(nodeIndex); isSchains = true; } else { completed = true; } if (completed) { require(nodes.completeExit(nodeIndex), "Finishing of node exit is failed"); nodes.changeNodeFinishTime(nodeIndex, now.add(isSchains ? constants.rotationDelay() : 0)); // Monitors monitors = Monitors(contractManager.getContract("Monitors")); // monitors.removeCheckedNodes(nodeIndex); // monitors.deleteMonitor(nodeIndex); nodes.deleteNodeForValidator(validatorId, nodeIndex); } } function deleteSchain(string calldata name) external { Schains schains = Schains(contractManager.getContract("Schains")); // schain owner checks inside deleteSchain schains.deleteSchain(msg.sender, name); } function deleteSchainByRoot(string calldata name) external onlyAdmin { Schains schains = Schains(contractManager.getContract("Schains")); schains.deleteSchainByRoot(name); } // function sendVerdict(uint fromMonitorIndex, Monitors.Verdict calldata verdict) external { // Nodes nodes = Nodes(contractManager.getContract("Nodes")); // require(nodes.isNodeExist(msg.sender, fromMonitorIndex), "Node does not exist for Message sender"); // Monitors monitors = Monitors(contractManager.getContract("Monitors")); // // additional checks for monitoring inside sendVerdict // monitors.sendVerdict(fromMonitorIndex, verdict); // } // function sendVerdicts(uint fromMonitorIndex, Monitors.Verdict[] calldata verdicts) external { // Nodes nodes = Nodes(contractManager.getContract("Nodes")); // require(nodes.isNodeExist(msg.sender, fromMonitorIndex), "Node does not exist for Message sender"); // Monitors monitors = Monitors(contractManager.getContract("Monitors")); // for (uint i = 0; i < verdicts.length; i++) { // // additional checks for monitoring inside sendVerdict // monitors.sendVerdict(fromMonitorIndex, verdicts[i]); // } // } function getBounty(uint nodeIndex) external { Nodes nodes = Nodes(contractManager.getContract("Nodes")); require(nodes.isNodeExist(msg.sender, nodeIndex), "Node does not exist for Message sender"); require(nodes.isTimeForReward(nodeIndex), "Not time for bounty"); require( nodes.isNodeActive(nodeIndex) || nodes.isNodeLeaving(nodeIndex), "Node is not Active and is not Leaving" ); Bounty bountyContract = Bounty(contractManager.getContract("Bounty")); uint averageDowntime; uint averageLatency; Monitors monitors = Monitors(contractManager.getContract("Monitors")); (averageDowntime, averageLatency) = monitors.calculateMetrics(nodeIndex); uint bounty = bountyContract.getBounty( nodeIndex, averageDowntime, averageLatency); nodes.changeNodeLastRewardDate(nodeIndex); // monitors.deleteMonitor(nodeIndex); // monitors.addMonitor(nodeIndex); if (bounty > 0) { _payBounty(bounty, nodes.getValidatorId(nodeIndex)); } _emitBountyEvent(nodeIndex, msg.sender, averageDowntime, averageLatency, bounty); } function initialize(address newContractsAddress) public override initializer { Permissions.initialize(newContractsAddress); _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); _erc1820.setInterfaceImplementer(address(this), _TOKENS_RECIPIENT_INTERFACE_HASH, address(this)); } function _payBounty(uint bounty, uint validatorId) private returns (bool) { IERC777 skaleToken = IERC777(contractManager.getContract("SkaleToken")); Distributor distributor = Distributor(contractManager.getContract("Distributor")); require( IMintableToken(address(skaleToken)).mint(address(distributor), bounty, abi.encode(validatorId), ""), "Token was not minted" ); } function _emitBountyEvent( uint nodeIndex, address from, uint averageDowntime, uint averageLatency, uint bounty ) private { Monitors monitors = Monitors(contractManager.getContract("Monitors")); uint previousBlockEvent = monitors.getLastBountyBlock(nodeIndex); monitors.setLastBountyBlock(nodeIndex); emit BountyGot( nodeIndex, from, averageDowntime, averageLatency, bounty, previousBlockEvent, block.timestamp, gasleft()); } }
// SPDX-License-Identifier: AGPL-3.0-only /* SkaleVerifier.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./Permissions.sol"; import "./SchainsInternal.sol"; import "./Precompiled.sol"; import "./FieldOperations.sol"; contract SkaleVerifier is Permissions { using Fp2Operations for Fp2Operations.Fp2Point; function verify( Fp2Operations.Fp2Point calldata signature, bytes32 hash, uint counter, uint hashA, uint hashB, G2Operations.G2Point calldata publicKey ) external view returns (bool) { if (!_checkHashToGroupWithHelper( hash, counter, hashA, hashB ) ) { return false; } uint newSignB; if (!(signature.a == 0 && signature.b == 0)) { newSignB = Fp2Operations.P.sub((signature.b % Fp2Operations.P)); } else { newSignB = signature.b; } require(G2Operations.isG1Point(signature.a, newSignB), "Sign not in G1"); require(G2Operations.isG1Point(hashA, hashB), "Hash not in G1"); G2Operations.G2Point memory g2 = G2Operations.getG2(); require( G2Operations.isG2(publicKey), "Public Key not in G2" ); return Precompiled.bn256Pairing( signature.a, newSignB, g2.x.b, g2.x.a, g2.y.b, g2.y.a, hashA, hashB, publicKey.x.b, publicKey.x.a, publicKey.y.b, publicKey.y.a ); } function initialize(address newContractsAddress) public override initializer { Permissions.initialize(newContractsAddress); } function _checkHashToGroupWithHelper( bytes32 hash, uint counter, uint hashA, uint hashB ) private pure returns (bool) { uint xCoord = uint(hash) % Fp2Operations.P; xCoord = (xCoord.add(counter)) % Fp2Operations.P; uint ySquared = addmod( mulmod(mulmod(xCoord, xCoord, Fp2Operations.P), xCoord, Fp2Operations.P), 3, Fp2Operations.P ); if (hashB < Fp2Operations.P.div(2) || mulmod(hashB, hashB, Fp2Operations.P) != ySquared || xCoord != hashA) { return false; } return true; } }
// SPDX-License-Identifier: AGPL-3.0-only /* StringUtils.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Vadim Yavorsky SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./SafeMath.sol"; library StringUtils { using SafeMath for uint; function strConcat(string memory a, string memory b) internal pure returns (string memory) { bytes memory _ba = bytes(a); bytes memory _bb = bytes(b); string memory ab = new string(_ba.length.add(_bb.length)); bytes memory strBytes = bytes(ab); uint k = 0; uint i = 0; for (i = 0; i < _ba.length; i++) { strBytes[k++] = _ba[i]; } for (i = 0; i < _bb.length; i++) { strBytes[k++] = _bb[i]; } return string(strBytes); } function uint2str(uint i) internal pure returns (string memory) { if (i == 0) { return "0"; } uint j = i; uint _i = i; uint len; while (j != 0) { len++; j /= 10; } bytes memory bstr = new bytes(len); uint k = len.sub(1); while (_i != 0) { bstr[k--] = byte(uint8(48 + _i % 10)); _i /= 10; } return string(bstr); } }
// SPDX-License-Identifier: AGPL-3.0-only /* TimeHelpers.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./SafeMath.sol"; import "./BokkyPooBahsDateTimeLibrary.sol"; /** * @title TimeHelpers * @dev The contract performs time operations. * * These functions are used to calculate monthly and Proof of Use epochs. */ contract TimeHelpers { using SafeMath for uint; uint constant private _ZERO_YEAR = 2020; function calculateProofOfUseLockEndTime(uint month, uint lockUpPeriodDays) external view returns (uint timestamp) { timestamp = BokkyPooBahsDateTimeLibrary.addDays(monthToTimestamp(month), lockUpPeriodDays); } function addDays(uint fromTimestamp, uint n) external pure returns (uint) { return BokkyPooBahsDateTimeLibrary.addDays(fromTimestamp, n); } function addMonths(uint fromTimestamp, uint n) external pure returns (uint) { return BokkyPooBahsDateTimeLibrary.addMonths(fromTimestamp, n); } function addYears(uint fromTimestamp, uint n) external pure returns (uint) { return BokkyPooBahsDateTimeLibrary.addYears(fromTimestamp, n); } function getCurrentMonth() external view virtual returns (uint) { return timestampToMonth(now); } function timestampToDay(uint timestamp) external view returns (uint) { uint wholeDays = timestamp / BokkyPooBahsDateTimeLibrary.SECONDS_PER_DAY; uint zeroDay = BokkyPooBahsDateTimeLibrary.timestampFromDate(_ZERO_YEAR, 1, 1) / BokkyPooBahsDateTimeLibrary.SECONDS_PER_DAY; require(wholeDays >= zeroDay, "Timestamp is too far in the past"); return wholeDays - zeroDay; } function timestampToYear(uint timestamp) external view virtual returns (uint) { uint year; (year, , ) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); require(year >= _ZERO_YEAR, "Timestamp is too far in the past"); return year - _ZERO_YEAR; } function timestampToMonth(uint timestamp) public view virtual returns (uint) { uint year; uint month; (year, month, ) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); require(year >= _ZERO_YEAR, "Timestamp is too far in the past"); month = month.sub(1).add(year.sub(_ZERO_YEAR).mul(12)); require(month > 0, "Timestamp is too far in the past"); return month; } function monthToTimestamp(uint month) public view virtual returns (uint timestamp) { uint year = _ZERO_YEAR; uint _month = month; year = year.add(_month.div(12)); _month = _month.mod(12); _month = _month.add(1); return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, _month, 1); } }
// SPDX-License-Identifier: AGPL-3.0-only /* TokenLaunchLocker.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; import "./Permissions.sol"; import "./ILocker.sol"; import "./ConstantsHolder.sol"; import "./MathUtils.sol"; import "./DelegationController.sol"; import "./TimeHelpers.sol"; import "./PartialDifferences.sol"; contract TokenLaunchLocker is Permissions, ILocker { using MathUtils for uint; using PartialDifferences for PartialDifferences.Value; /** * @dev Emitted when an `amount` is unlocked. */ event Unlocked( address holder, uint amount ); /** * @dev Emitted when an `amount` is locked. */ event Locked( address holder, uint amount ); struct DelegatedAmountAndMonth { uint delegated; uint month; } // holder => tokens mapping (address => uint) private _locked; // holder => tokens mapping (address => PartialDifferences.Value) private _delegatedAmount; mapping (address => DelegatedAmountAndMonth) private _totalDelegatedAmount; // delegationId => tokens mapping (uint => uint) private _delegationAmount; function lock(address holder, uint amount) external allow("TokenLaunchManager") { _locked[holder] = _locked[holder].add(amount); emit Locked(holder, amount); } function handleDelegationAdd( address holder, uint delegationId, uint amount, uint month) external allow("DelegationController") { if (_locked[holder] > 0) { TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); uint currentMonth = timeHelpers.getCurrentMonth(); uint fromLocked = amount; uint locked = _locked[holder].boundedSub(_getAndUpdateDelegatedAmount(holder, currentMonth)); if (fromLocked > locked) { fromLocked = locked; } if (fromLocked > 0) { require(_delegationAmount[delegationId] == 0, "Delegation was already added"); _addToDelegatedAmount(holder, fromLocked, month); _addToTotalDelegatedAmount(holder, fromLocked, month); _delegationAmount[delegationId] = fromLocked; } } } function handleDelegationRemoving( address holder, uint delegationId, uint month) external allow("DelegationController") { if (_delegationAmount[delegationId] > 0) { if (_locked[holder] > 0) { _removeFromDelegatedAmount(holder, _delegationAmount[delegationId], month); } delete _delegationAmount[delegationId]; } } function getAndUpdateLockedAmount(address wallet) external override returns (uint) { if (_locked[wallet] > 0) { DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController")); TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); uint currentMonth = timeHelpers.getCurrentMonth(); if (_totalDelegatedSatisfiesProofOfUserCondition(wallet) && timeHelpers.calculateProofOfUseLockEndTime( _totalDelegatedAmount[wallet].month, constantsHolder.proofOfUseLockUpPeriodDays() ) <= now) { _unlock(wallet); return 0; } else { uint lockedByDelegationController = _getAndUpdateDelegatedAmount(wallet, currentMonth) .add(delegationController.getLockedInPendingDelegations(wallet)); if (_locked[wallet] > lockedByDelegationController) { return _locked[wallet].boundedSub(lockedByDelegationController); } else { return 0; } } } else { return 0; } } function getAndUpdateForbiddenForDelegationAmount(address) external override returns (uint) { return 0; } function initialize(address contractManagerAddress) public override initializer { Permissions.initialize(contractManagerAddress); } // private function _getAndUpdateDelegatedAmount(address holder, uint currentMonth) private returns (uint) { return _delegatedAmount[holder].getAndUpdateValue(currentMonth); } function _addToDelegatedAmount(address holder, uint amount, uint month) private { _delegatedAmount[holder].addToValue(amount, month); } function _removeFromDelegatedAmount(address holder, uint amount, uint month) private { _delegatedAmount[holder].subtractFromValue(amount, month); } function _addToTotalDelegatedAmount(address holder, uint amount, uint month) private { require( _totalDelegatedAmount[holder].month == 0 || _totalDelegatedAmount[holder].month <= month, "Can't add to total delegated in the past"); // do not update counter if it is big enough // because it will override month value if (!_totalDelegatedSatisfiesProofOfUserCondition(holder)) { _totalDelegatedAmount[holder].delegated = _totalDelegatedAmount[holder].delegated.add(amount); _totalDelegatedAmount[holder].month = month; } } function _unlock(address holder) private { emit Unlocked(holder, _locked[holder]); delete _locked[holder]; _deleteDelegatedAmount(holder); _deleteTotalDelegatedAmount(holder); } function _deleteDelegatedAmount(address holder) private { _delegatedAmount[holder].clear(); } function _deleteTotalDelegatedAmount(address holder) private { delete _totalDelegatedAmount[holder].delegated; delete _totalDelegatedAmount[holder].month; } function _totalDelegatedSatisfiesProofOfUserCondition(address holder) private view returns (bool) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); return _totalDelegatedAmount[holder].delegated.mul(100) >= _locked[holder].mul(constantsHolder.proofOfUseDelegationPercentage()); } }
// SPDX-License-Identifier: AGPL-3.0-only /* TokenState.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./Permissions.sol"; import "./DelegationController.sol"; import "./TimeHelpers.sol"; import "./ILocker.sol"; /** * @title Token State * @dev This contract manages lockers to control token transferability. * * See ILocker. */ contract TokenState is Permissions, ILocker { /** * @dev Emitted when a contract is added to the locker. */ event LockerWasAdded( string locker ); /** * @dev Emitted when a contract is removed from the locker. */ event LockerWasRemoved( string locker ); string[] private _lockers; /** * @dev Return and update the total locked amount of a given `holder`. * * @param holder address of the token holder * @return total locked amount */ function getAndUpdateLockedAmount(address holder) external override returns (uint) { uint locked = 0; for (uint i = 0; i < _lockers.length; ++i) { ILocker locker = ILocker(contractManager.getContract(_lockers[i])); locked = locked.add(locker.getAndUpdateLockedAmount(holder)); } return locked; } /** * @dev Return and update the total locked and un-delegatable amount of a given `holder`. * * @param holder address of the token holder * @return amount total slashed amount (non-transferable and non-delegatable) */ function getAndUpdateForbiddenForDelegationAmount(address holder) external override returns (uint amount) { uint forbidden = 0; for (uint i = 0; i < _lockers.length; ++i) { ILocker locker = ILocker(contractManager.getContract(_lockers[i])); forbidden = forbidden.add(locker.getAndUpdateForbiddenForDelegationAmount(holder)); } return forbidden; } /** * @dev Allows the Owner to remove a contract from the locker. * * Emits a LockerWasRemoved event. * * @param locker string name of contract to remove from locker */ function removeLocker(string calldata locker) external onlyOwner { uint index; bytes32 hash = keccak256(abi.encodePacked(locker)); for (index = 0; index < _lockers.length; ++index) { if (keccak256(abi.encodePacked(_lockers[index])) == hash) { break; } } if (index < _lockers.length) { if (index < _lockers.length.sub(1)) { _lockers[index] = _lockers[_lockers.length.sub(1)]; } delete _lockers[_lockers.length.sub(1)]; _lockers.pop(); emit LockerWasRemoved(locker); } } function initialize(address contractManagerAddress) public override initializer { Permissions.initialize(contractManagerAddress); addLocker("DelegationController"); addLocker("Punisher"); addLocker("TokenLaunchLocker"); } /** * @dev Allows the Owner to add a contract to the Locker. * * Emits a LockerWasAdded event. * * @param locker string name of contract to add to locker */ function addLocker(string memory locker) public onlyOwner { _lockers.push(locker); emit LockerWasAdded(locker); } }
// SPDX-License-Identifier: AGPL-3.0-only /* ValidatorService.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev @author Artem Payvin @author Vadim Yavorsky SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import "./ECDSA.sol"; import "./Permissions.sol"; import "./ConstantsHolder.sol"; import "./DelegationController.sol"; /** * @title ValidatorService * @dev This contract handles all validator operations including registration, * node management, validator-specific delegation parameters, and more. * * Validators register an address, and use this address to accept delegations and * register nodes. * */ contract ValidatorService is Permissions { using ECDSA for bytes32; struct Validator { string name; address validatorAddress; address requestedAddress; string description; uint feeRate; uint registrationTime; uint minimumDelegationAmount; bool acceptNewRequests; } /** * @dev Emitted when a validator registers. */ event ValidatorRegistered( uint validatorId ); /** * @dev Emitted when a validator address changes. */ event ValidatorAddressChanged( uint validatorId, address newAddress ); event ValidatorWasEnabled( uint validatorId ); event ValidatorWasDisabled( uint validatorId ); /** * @dev Emitted when a node address is linked to a validator. */ event NodeAddressWasAdded( uint validatorId, address nodeAddress ); /** * @dev Emitted when a node address is unlinked from a validator. */ event NodeAddressWasRemoved( uint validatorId, address nodeAddress ); mapping (uint => Validator) public validators; mapping (uint => bool) private _trustedValidators; uint[] public trustedValidatorsList; // address => validatorId mapping (address => uint) private _validatorAddressToId; // address => validatorId mapping (address => uint) private _nodeAddressToValidatorId; // validatorId => nodeAddress[] mapping (uint => address[]) private _nodeAddresses; uint public numberOfValidators; bool public useWhitelist; modifier checkValidatorExists(uint validatorId) { require(validatorExists(validatorId), "Validator with such ID does not exist"); _; } /** * @dev Creates a new validator Id. * * Requirements: * * - sender must not already have registered a validator Id. * - fee rate must be between 0 - 1000‰. Note: per mille! * * Emits ValidatorRegistered event. * * @param name string * @param description string * @param feeRate uint Fee charged on delegations by the validator per mille * @param minimumDelegationAmount uint Minimum delegation amount accepted by the validator */ function registerValidator( string calldata name, string calldata description, uint feeRate, uint minimumDelegationAmount ) external returns (uint validatorId) { require(!validatorAddressExists(msg.sender), "Validator with such address already exists"); require(feeRate < 1000, "Fee rate of validator should be lower than 100%"); validatorId = ++numberOfValidators; validators[validatorId] = Validator( name, msg.sender, address(0), description, feeRate, now, minimumDelegationAmount, true ); _setValidatorAddress(validatorId, msg.sender); emit ValidatorRegistered(validatorId); } function enableValidator(uint validatorId) external checkValidatorExists(validatorId) onlyAdmin { require(!_trustedValidators[validatorId], "Validator is already enabled"); _trustedValidators[validatorId] = true; trustedValidatorsList.push(validatorId); emit ValidatorWasEnabled(validatorId); } function disableValidator(uint validatorId) external checkValidatorExists(validatorId) onlyAdmin { require(_trustedValidators[validatorId], "Validator is already disabled"); _trustedValidators[validatorId] = false; uint position = _find(trustedValidatorsList, validatorId); if (position < trustedValidatorsList.length) { trustedValidatorsList[position] = trustedValidatorsList[trustedValidatorsList.length.sub(1)]; } trustedValidatorsList.pop(); emit ValidatorWasDisabled(validatorId); } /** * @dev Owner can disable the validator whitelist. Once turned off the * whitelist cannot be re-enabled. */ function disableWhitelist() external onlyOwner { useWhitelist = false; } /** * @dev Allows a validator to request a new address. * * Requirements: * * - new address must not be null * - new address must not be already registered as a validator * * @param newValidatorAddress address */ function requestForNewAddress(address newValidatorAddress) external { require(newValidatorAddress != address(0), "New address cannot be null"); require(_validatorAddressToId[newValidatorAddress] == 0, "Address already registered"); // check Validator Exist inside getValidatorId uint validatorId = getValidatorId(msg.sender); validators[validatorId].requestedAddress = newValidatorAddress; } function confirmNewAddress(uint validatorId) external checkValidatorExists(validatorId) { require( getValidator(validatorId).requestedAddress == msg.sender, "The validator address cannot be changed because it is not the actual owner" ); delete validators[validatorId].requestedAddress; _setValidatorAddress(validatorId, msg.sender); emit ValidatorAddressChanged(validatorId, validators[validatorId].validatorAddress); } /** * @dev Links a given node address. * * Requirements: * * - the given signature must be valid. * - the address must not be assigned to a validator. * * Emits NodeAddressWasAdded event. * * @param nodeAddress address * @param sig bytes signature of validator Id by node operator. */ function linkNodeAddress(address nodeAddress, bytes calldata sig) external { // check Validator Exist inside getValidatorId uint validatorId = getValidatorId(msg.sender); require( keccak256(abi.encodePacked(validatorId)).toEthSignedMessageHash().recover(sig) == nodeAddress, "Signature is not pass" ); require(_validatorAddressToId[nodeAddress] == 0, "Node address is a validator"); _addNodeAddress(validatorId, nodeAddress); emit NodeAddressWasAdded(validatorId, nodeAddress); } /** * @dev Unlinks a given node address from a validator. * * Emits NodeAddressWasRemoved event. * * @param nodeAddress address */ function unlinkNodeAddress(address nodeAddress) external { // check Validator Exist inside getValidatorId uint validatorId = getValidatorId(msg.sender); _removeNodeAddress(validatorId, nodeAddress); emit NodeAddressWasRemoved(validatorId, nodeAddress); } function setValidatorMDA(uint minimumDelegationAmount) external { // check Validator Exist inside getValidatorId uint validatorId = getValidatorId(msg.sender); validators[validatorId].minimumDelegationAmount = minimumDelegationAmount; } /** * @dev Allows a validator to set a new validator name. * * @param newName string */ function setValidatorName(string calldata newName) external { // check Validator Exist inside getValidatorId uint validatorId = getValidatorId(msg.sender); validators[validatorId].name = newName; } /** * @dev Allows a validator to set a new validator description. * * @param newDescription string */ function setValidatorDescription(string calldata newDescription) external { // check Validator Exist inside getValidatorId uint validatorId = getValidatorId(msg.sender); validators[validatorId].description = newDescription; } /** * @dev Allows a validator to start accepting new delegation requests. * * Requirements: * * - validator must not have already enabled accepting new requests */ function startAcceptingNewRequests() external { // check Validator Exist inside getValidatorId uint validatorId = getValidatorId(msg.sender); require(!isAcceptingNewRequests(validatorId), "Accepting request is already enabled"); validators[validatorId].acceptNewRequests = true; } /** * @dev Allows a validator to stop accepting new delegation requests. * * Requirements: * * - validator must not have already stopped accepting new requests */ function stopAcceptingNewRequests() external { // check Validator Exist inside getValidatorId uint validatorId = getValidatorId(msg.sender); require(isAcceptingNewRequests(validatorId), "Accepting request is already disabled"); validators[validatorId].acceptNewRequests = false; } /** * @dev Returns the amount of validator bond. * * @param validatorId uint ID of validator to return the amount of locked funds * @return bondAmount uint the amount of self-delegated funds by the validator */ function getAndUpdateBondAmount(uint validatorId) external returns (uint) { DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController") ); return delegationController.getAndUpdateDelegatedByHolderToValidatorNow( getValidator(validatorId).validatorAddress, validatorId ); } function getMyNodesAddresses() external view returns (address[] memory) { return getNodeAddresses(getValidatorId(msg.sender)); } /** * @dev Returns a list of trusted validators. * * @return uint[] trusted validators */ function getTrustedValidators() external view returns (uint[] memory) { return trustedValidatorsList; } function checkMinimumDelegation(uint validatorId, uint amount) external view checkValidatorExists(validatorId) allow("DelegationController") returns (bool) { return validators[validatorId].minimumDelegationAmount <= amount ? true : false; } function checkValidatorAddressToId(address validatorAddress, uint validatorId) external view returns (bool) { return getValidatorId(validatorAddress) == validatorId ? true : false; } function getValidatorIdByNodeAddress(address nodeAddress) external view returns (uint validatorId) { validatorId = _nodeAddressToValidatorId[nodeAddress]; require(validatorId != 0, "Node address is not assigned to a validator"); } function isAuthorizedValidator(uint validatorId) external view checkValidatorExists(validatorId) returns (bool) { return _trustedValidators[validatorId] || !useWhitelist; } function initialize(address contractManagerAddress) public override initializer { Permissions.initialize(contractManagerAddress); useWhitelist = true; } function getNodeAddresses(uint validatorId) public view returns (address[] memory) { return _nodeAddresses[validatorId]; } function validatorExists(uint validatorId) public view returns (bool) { return validatorId <= numberOfValidators && validatorId != 0; } function validatorAddressExists(address validatorAddress) public view returns (bool) { return _validatorAddressToId[validatorAddress] != 0; } function checkIfValidatorAddressExists(address validatorAddress) public view { require(validatorAddressExists(validatorAddress), "Validator with given address does not exist"); } function getValidator(uint validatorId) public view checkValidatorExists(validatorId) returns (Validator memory) { return validators[validatorId]; } function getValidatorId(address validatorAddress) public view returns (uint) { checkIfValidatorAddressExists(validatorAddress); return _validatorAddressToId[validatorAddress]; } function isAcceptingNewRequests(uint validatorId) public view checkValidatorExists(validatorId) returns (bool) { return validators[validatorId].acceptNewRequests; } // private function _setValidatorAddress(uint validatorId, address validatorAddress) private { if (_validatorAddressToId[validatorAddress] == validatorId) { return; } require(_validatorAddressToId[validatorAddress] == 0, "Address is in use by another validator"); address oldAddress = validators[validatorId].validatorAddress; delete _validatorAddressToId[oldAddress]; _nodeAddressToValidatorId[validatorAddress] = validatorId; validators[validatorId].validatorAddress = validatorAddress; _validatorAddressToId[validatorAddress] = validatorId; } function _addNodeAddress(uint validatorId, address nodeAddress) private { if (_nodeAddressToValidatorId[nodeAddress] == validatorId) { return; } require(_nodeAddressToValidatorId[nodeAddress] == 0, "Validator cannot override node address"); _nodeAddressToValidatorId[nodeAddress] = validatorId; _nodeAddresses[validatorId].push(nodeAddress); } function _removeNodeAddress(uint validatorId, address nodeAddress) private { require(_nodeAddressToValidatorId[nodeAddress] == validatorId, "Validator does not have permissions to unlink node"); delete _nodeAddressToValidatorId[nodeAddress]; for (uint i = 0; i < _nodeAddresses[validatorId].length; ++i) { if (_nodeAddresses[validatorId][i] == nodeAddress) { if (i + 1 < _nodeAddresses[validatorId].length) { _nodeAddresses[validatorId][i] = _nodeAddresses[validatorId][_nodeAddresses[validatorId].length.sub(1)]; } delete _nodeAddresses[validatorId][_nodeAddresses[validatorId].length.sub(1)]; _nodeAddresses[validatorId].pop(); break; } } } function _find(uint[] memory array, uint index) private pure returns (uint) { uint i; for (i = 0; i < array.length; i++) { if (array[i] == index) { return i; } } return array.length; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delegationId","type":"uint256"}],"name":"DelegationAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delegationId","type":"uint256"}],"name":"DelegationProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delegationId","type":"uint256"}],"name":"DelegationRequestCanceledByUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delegationId","type":"uint256"}],"name":"UndelegationRequested","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"delegationId","type":"uint256"}],"name":"acceptPendingDelegation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"delegationId","type":"uint256"}],"name":"cancelPendingDelegation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"confiscate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractManager","outputs":[{"internalType":"contract ContractManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"delegationPeriod","type":"uint256"},{"internalType":"string","name":"info","type":"string"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"delegations","outputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"validatorId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"delegationPeriod","type":"uint256"},{"internalType":"uint256","name":"created","type":"uint256"},{"internalType":"uint256","name":"started","type":"uint256"},{"internalType":"uint256","name":"finished","type":"uint256"},{"internalType":"string","name":"info","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"delegationsByHolder","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"delegationsByValidator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"getAndUpdateDelegatedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"validatorId","type":"uint256"}],"name":"getAndUpdateDelegatedByHolderToValidatorNow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorId","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"getAndUpdateDelegatedToValidator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorId","type":"uint256"}],"name":"getAndUpdateDelegatedToValidatorNow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"validatorId","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"getAndUpdateEffectiveDelegatedByHolderToValidator","outputs":[{"internalType":"uint256","name":"effectiveDelegated","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorId","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"getAndUpdateEffectiveDelegatedToValidator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"getAndUpdateForbiddenForDelegationAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"getAndUpdateLockedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"delegationId","type":"uint256"}],"name":"getDelegation","outputs":[{"components":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"validatorId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"delegationPeriod","type":"uint256"},{"internalType":"uint256","name":"created","type":"uint256"},{"internalType":"uint256","name":"started","type":"uint256"},{"internalType":"uint256","name":"finished","type":"uint256"},{"internalType":"string","name":"info","type":"string"}],"internalType":"struct DelegationController.Delegation","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"getDelegationsByHolderLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorId","type":"uint256"}],"name":"getDelegationsByValidatorLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"validatorId","type":"uint256"}],"name":"getFirstDelegationMonth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"getLockedInPendingDelegations","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"delegationId","type":"uint256"}],"name":"getState","outputs":[{"internalType":"enum DelegationController.State","name":"state","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"hasUnprocessedSlashes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractsAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"processAllSlashes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"processSlashes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"delegationId","type":"uint256"}],"name":"requestUndelegation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50615f1980620000216000396000f3fe608060405234801561001057600080fd5b50600436106102115760003560e01c806356574b8c11610125578063b39e12cf116100ad578063ca15c8731161007c578063ca15c8731461049a578063d547741f146104ad578063dda641ae146104c0578063fa8dacba14610216578063ff1f7799146104d357610211565b8063b39e12cf14610445578063b86315851461044d578063c4336c1c14610460578063c4d66de81461048757610211565b806391d14854116100f457806391d14854146103f15780639654ff16146104045780639ac1c4ad146104175780639c3e452f1461042a578063a217fddf1461043d57610211565b806356574b8c146103985780635fd55293146103ab5780637ce845d0146103be5780639010d07c146103d157610211565b8063248a9ca3116101a85780632f7263cd116101775780632f7263cd1461031f57806336568abe1461033f5780633d42b1ce14610352578063416880b01461036557806344c9af281461037857610211565b8063248a9ca3146102d357806327040f68146102e657806327e5455a146102f95780632f2ff15d1461030c57610211565b80631d703812116101e45780631d703812146102875780631d9c7f0a1461029a5780631da42e5e146102ad57806321eb5859146102c057610211565b80630b975991146102165780630dd357011461023f5780630e01bff81461025f5780631c8a253e14610272575b600080fd5b610229610224366004615046565b6104e6565b6040516102369190615324565b60405180910390f35b61025261024d3660046150fd565b6104f9565b6040516102369190615e27565b61022961026d3660046150a9565b61063c565b61028561028036600461507e565b610794565b005b6102296102953660046150fd565b6107aa565b6102296102a8366004615144565b6107b8565b6102856102bb366004615144565b6107e6565b6102856102ce36600461517d565b610a25565b6102296102e13660046150fd565b611065565b6102296102f4366004615046565b61107a565b6102856103073660046150fd565b611085565b61028561031a366004615115565b6117d2565b61033261032d366004615046565b611816565b6040516102369190615319565b61028561034d366004615115565b61184b565b6102296103603660046150fd565b61188d565b610229610373366004615144565b61189f565b61038b6103863660046150fd565b6119ca565b604051610236919061532d565b6102296103a636600461507e565b611c29565b6102856103b9366004615046565b611c42565b6102296103cc366004615046565b611c50565b6103e46103df366004615144565b611cab565b6040516102369190615250565b6103326103ff366004615115565b611cd2565b61022961041236600461507e565b611cf0565b6102856104253660046150fd565b611d1c565b610229610438366004615144565b611e6f565b610229611f8a565b6103e4611f8f565b61028561045b3660046150fd565b611f9e565b61047361046e3660046150fd565b612434565b6040516102369897969594939291906152c4565b610285610495366004615046565b61251d565b6102296104a83660046150fd565b6125a9565b6102856104bb366004615115565b6125c0565b6102296104ce366004615046565b6125fa565b6102296104e136600461507e565b612615565b60006104f182612629565b90505b919050565b610501614f2f565b6098548290811061052d5760405162461bcd60e51b815260040161052490615cc0565b60405180910390fd5b6098838154811061053a57fe5b600091825260209182902060408051610100808201835260089490940290920180546001600160a01b0316835260018082015484870152600280830154858501526003830154606086015260048301546080860152600583015460a0860152600683015460c08601526007830180548551938116159097026000190190961604601f81018790048702820187019093528281529294909360e086019392909183018282801561062a5780601f106105ff5761010080835404028352916020019161062a565b820191906000526020600020905b81548152906001019060200180831161060d57829003601f168201915b50505050508152505091505b50919050565b604080518082018252600b81526a2234b9ba3934b13aba37b960a91b602080830191909152609754925160009333926001600160a01b039091169163ec56a3739161068991869101615234565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004016106bb9190615324565b60206040518083038186803b1580156106d357600080fd5b505afa1580156106e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070b9190615062565b6001600160a01b03161480610723575061072361264c565b61073f5760405162461bcd60e51b815260040161052490615d40565b606061074a8661265e565b6001600160a01b038716600090815260a1602090815260408083208984529091529020909150610780908563ffffffff61266b16565b925061078b816127b2565b50509392505050565b6107a66107a183836129b4565b6127b2565b5050565b60006104f182610438612c74565b609960205281600052604060002081815481106107d157fe5b90600052602060002001600091509150505481565b6040805180820182526008815267283ab734b9b432b960c11b6020808301919091526097549251919233926001600160a01b039091169163ec56a3739161082f91869101615234565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004016108619190615324565b60206040518083038186803b15801561087957600080fd5b505afa15801561088d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b19190615062565b6001600160a01b031614806108c957506108c961264c565b6108e55760405162461bcd60e51b815260040161052490615d40565b60006108ef612c74565b90506108f9614f7d565b6000858152609c6020526040902061091890858463ffffffff612d7016565b6000868152609d6020526040902090915061093a90828463ffffffff612e4216565b6000858152609e60205260409020610953908284612f92565b60408051606081018252918252602080830196875290820192835260a28054600181018255600091909152915180517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42d60049094029384015501517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42e82015593517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42f850155517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf430909301929092555050565b609754604051633581777360e01b81526000916001600160a01b031690633581777390610a5490600401615dae565b60206040518083038186803b158015610a6c57600080fd5b505afa158015610a80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa49190615062565b609754604051633581777360e01b81529192506000916001600160a01b0390911690633581777390610ad8906004016159f9565b60206040518083038186803b158015610af057600080fd5b505afa158015610b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b289190615062565b609754604051633581777360e01b81529192506000916001600160a01b0390911690633581777390610b5c90600401615871565b60206040518083038186803b158015610b7457600080fd5b505afa158015610b88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bac9190615062565b609754604051633581777360e01b81529192506000916001600160a01b0390911690633581777390610be090600401615ac3565b60206040518083038186803b158015610bf857600080fd5b505afa158015610c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c309190615062565b6040516370cb318960e01b81529091506001600160a01b038516906370cb318990610c61908c908c90600401615e94565b60206040518083038186803b158015610c7957600080fd5b505afa158015610c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb191906150dd565b610ccd5760405162461bcd60e51b815260040161052490615c12565b60405163f93c86f160e01b81526001600160a01b0385169063f93c86f190610cf9908c90600401615324565b60206040518083038186803b158015610d1157600080fd5b505afa158015610d25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4991906150dd565b610d655760405162461bcd60e51b81526004016105249061551d565b60405163a795d29360e01b81526001600160a01b0384169063a795d29390610d91908a90600401615324565b60206040518083038186803b158015610da957600080fd5b505afa158015610dbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de191906150dd565b610dfd5760405162461bcd60e51b815260040161052490615bcd565b60405163461a6f3f60e11b81526001600160a01b03851690638c34de7e90610e29908c90600401615324565b60206040518083038186803b158015610e4157600080fd5b505afa158015610e55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7991906150dd565b610e955760405162461bcd60e51b8152600401610524906155a3565b610e9f338a61308e565b506060610eab3361265e565b90506000610ef2338c8c8c8c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061321a92505050565b90506000846001600160a01b03166370a08231336040518263ffffffff1660e01b8152600401610f229190615250565b60206040518083038186803b158015610f3a57600080fd5b505afa158015610f4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f729190615165565b90506000846001600160a01b0316630b975991336040518263ffffffff1660e01b8152600401610fa29190615250565b602060405180830381600087803b158015610fbc57600080fd5b505af1158015610fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff49190615165565b9050808210156110165760405162461bcd60e51b8152600401610524906158cc565b7f839237f8da6208af7e49773f22501b3082aaae94d5b6ce8ee96f117835fe2f67836040516110459190615324565b60405180910390a1611056846127b2565b50505050505050505050505050565b60009081526065602052604090206002015490565b60006104f182613479565b609854819081106110a85760405162461bcd60e51b815260040161052490615cc0565b60046110b3836119ca565b60068111156110be57fe5b146110db5760405162461bcd60e51b8152600401610524906157ba565b609754604051633581777360e01b81526000916001600160a01b03169063358177739061110a90600401615dae565b60206040518083038186803b15801561112257600080fd5b505afa158015611136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115a9190615062565b9050336001600160a01b03166098848154811061117357fe5b60009182526020909120600890910201546001600160a01b031614806112b357506040516224441f60e71b81526001600160a01b038216906312220f80906111bf903390600401615250565b60206040518083038186803b1580156111d757600080fd5b505afa1580156111eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120f91906150dd565b80156112b35750604051630ba7341960e11b81526001600160a01b0382169063174e683290611242903390600401615250565b60206040518083038186803b15801561125a57600080fd5b505afa15801561126e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112929190615165565b6098848154811061129f57fe5b906000526020600020906008020160010154145b6112cf5760405162461bcd60e51b815260040161052490615cf7565b609754604051633581777360e01b81526000916001600160a01b0316906335817773906112fe90600401615684565b60206040518083038186803b15801561131657600080fd5b505afa15801561132a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134e9190615062565b609754604051633581777360e01b81529192506000916001600160a01b0390911690633581777390611382906004016159f9565b60206040518083038186803b15801561139a57600080fd5b505afa1580156113ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d29190615062565b9050611426609886815481106113e457fe5b6000918252602090912060089091020154609880546001600160a01b03909216918890811061140f57fe5b9060005260206000209060080201600101546134b7565b61142f33611c42565b6114388561358e565b6098868154811061144557fe5b906000526020600020906008020160060181905550600061146586613695565b90506114ae6098878154811061147757fe5b906000526020600020906008020160010154826098898154811061149757fe5b9060005260206000209060080201600601546137ce565b611508609887815481106114be57fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b031682609889815481106114f157fe5b9060005260206000209060080201600601546137ed565b61157a6098878154811061151857fe5b6000918252602090912060089091020154609880546001600160a01b03909216918990811061154357fe5b9060005260206000209060080201600101548360988a8154811061156357fe5b906000526020600020906008020160060154613816565b6000611626836001600160a01b031663f5b98f4160988a8154811061159b57fe5b9060005260206000209060080201600301546040518263ffffffff1660e01b81526004016115c99190615324565b60206040518083038186803b1580156115e157600080fd5b505afa1580156115f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116199190615165565b839063ffffffff61384a16565b905061166f6098888154811061163857fe5b9060005260206000209060080201600101548260988a8154811061165857fe5b906000526020600020906008020160060154613884565b6116e16098888154811061167f57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918a9081106116aa57fe5b9060005260206000209060080201600101548360988b815481106116ca57fe5b9060005260206000209060080201600601546138a3565b836001600160a01b0316630d4e8fd1609889815481106116fd57fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b03168960988b8154811061173057fe5b9060005260206000209060080201600601546040518463ffffffff1660e01b81526004016117609392919061527d565b600060405180830381600087803b15801561177a57600080fd5b505af115801561178e573d6000803e3d6000fd5b505050507fb0142de902382ce87e0ae1e5ec0699b26d25bec2eeb06bca82e1253099b3119c876040516117c19190615324565b60405180910390a150505050505050565b6000828152606560205260409020600201546117f0906103ff6138d7565b61180c5760405162461bcd60e51b8152600401610524906153e6565b6107a682826138db565b60006118218261394a565b80156104f157505060a2546001600160a01b0391909116600090815260a360205260409020541090565b6118536138d7565b6001600160a01b0316816001600160a01b0316146118835760405162461bcd60e51b815260040161052490615dd8565b6107a68282613967565b60009081526099602052604090205490565b604080518082018252600b81526a2234b9ba3934b13aba37b960a91b602080830191909152609754925160009333926001600160a01b039091169163ec56a373916118ec91869101615234565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b815260040161191e9190615324565b60206040518083038186803b15801561193657600080fd5b505afa15801561194a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196e9190615062565b6001600160a01b03161480611986575061198661264c565b6119a25760405162461bcd60e51b815260040161052490615d40565b6000848152609d602052604090206119c0908463ffffffff61266b16565b91505b5092915050565b609854600090829081106119f05760405162461bcd60e51b815260040161052490615cc0565b609883815481106119fd57fe5b90600052602060002090600802016005015460001415611b845760988381548110611a2457fe5b90600052602060002090600802016006015460001415611b7b57609754604051633581777360e01b81526000916001600160a01b031690633581777390611a6d9060040161565f565b60206040518083038186803b158015611a8557600080fd5b505afa158015611a99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abd9190615062565b9050806001600160a01b031663bf64d84960988681548110611adb57fe5b9060005260206000209060080201600401546040518263ffffffff1660e01b8152600401611b099190615324565b60206040518083038186803b158015611b2157600080fd5b505afa158015611b35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b599190615165565b611b61612c74565b1415611b71576000925050610636565b6003925050610636565b60029150610636565b60988381548110611b9157fe5b906000526020600020906008020160050154611bab612c74565b1015611bba5760019150610636565b60988381548110611bc757fe5b90600052602060002090600802016006015460001415611bea5760049150610636565b60988381548110611bf757fe5b906000526020600020906008020160060154611c11612c74565b1015611c205760059150610636565b60069150610636565b609a60205281600052604060002081815481106107d157fe5b611c4d816000610794565b50565b600080611c5b612c74565b6001600160a01b038416600090815260a56020526040902060010154909150811115611c8b5760009150506104f4565b50506001600160a01b038116600090815260a560205260409020546104f4565b6000828152606560205260408120611cc9908363ffffffff6139d616565b90505b92915050565b6000828152606560205260408120611cc9908363ffffffff6139e216565b6001600160a01b0391909116600090815260a46020908152604080832093835260019093019052205490565b60985481908110611d3f5760405162461bcd60e51b815260040161052490615cc0565b60988281548110611d4c57fe5b60009182526020909120600890910201546001600160a01b03163314611d845760405162461bcd60e51b815260040161052490615354565b6000611d8f836119ca565b6006811115611d9a57fe5b14611db75760405162461bcd60e51b815260040161052490615b29565b611dbf612c74565b60988381548110611dcc57fe5b906000526020600020906008020160060181905550611e3360988381548110611df157fe5b6000918252602090912060089091020154609880546001600160a01b039092169185908110611e1c57fe5b9060005260206000209060080201600201546139f7565b507fc42cff898171c085fa87ecad4869a5fb22753dddf61048199b8c740c2109fb1182604051611e639190615324565b60405180910390a15050565b60408051808201825260058152644e6f64657360d81b602080830191909152609754925160009333926001600160a01b039091169163ec56a37391611eb691869101615234565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b8152600401611ee89190615324565b60206040518083038186803b158015611f0057600080fd5b505afa158015611f14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f389190615062565b6001600160a01b03161480611f505750611f5061264c565b611f6c5760405162461bcd60e51b815260040161052490615d40565b6000848152609c602052604090206119c0908463ffffffff613ac316565b600081565b6097546001600160a01b031681565b60985481908110611fc15760405162461bcd60e51b815260040161052490615cc0565b609754604051633581777360e01b81526000916001600160a01b031690633581777390611ff090600401615dae565b60206040518083038186803b15801561200857600080fd5b505afa15801561201c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120409190615062565b9050806001600160a01b031663bed5012e336098868154811061205f57fe5b9060005260206000209060080201600101546040518363ffffffff1660e01b815260040161208e929190615264565b60206040518083038186803b1580156120a657600080fd5b505afa1580156120ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120de91906150dd565b6120fa5760405162461bcd60e51b81526004016105249061583c565b61214c6098848154811061210a57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918690811061213557fe5b90600052602060002090600802016001015461308e565b506000612158846119ca565b9050600081600681111561216857fe5b1461223357600181600681111561217b57fe5b14806121925750600481600681111561219057fe5b145b806121a8575060058160068111156121a657fe5b145b806121be575060068160068111156121bc57fe5b145b156121db5760405162461bcd60e51b8152600401610524906154d5565b60028160068111156121e957fe5b14156122075760405162461bcd60e51b815260040161052490615c6f565b600381600681111561221557fe5b14156122335760405162461bcd60e51b8152600401610524906156f1565b600081600681111561224157fe5b1461225e5760405162461bcd60e51b815260040161052490615b86565b609754604051633581777360e01b81526000916001600160a01b03169063358177739061228d90600401615684565b60206040518083038186803b1580156122a557600080fd5b505afa1580156122b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122dd9190615062565b90506060612310609887815481106122f157fe5b60009182526020909120600890910201546001600160a01b031661265e565b905061231b86613be3565b816001600160a01b03166394df393f6098888154811061233757fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b03168860988a8154811061236a57fe5b90600052602060002090600802016002015460988b8154811061238957fe5b9060005260206000209060080201600501546040518563ffffffff1660e01b81526004016123ba949392919061529e565b600060405180830381600087803b1580156123d457600080fd5b505af11580156123e8573d6000803e3d6000fd5b505050506123f5816127b2565b7fdb0c41de0e1a6e61f3ea29d9618edd8bfe8cb4e041a267c54eec70418341272d866040516124249190615324565b60405180910390a1505050505050565b6098818154811061244157fe5b60009182526020918290206008909102018054600180830154600280850154600386015460048701546005880154600689015460078a01805460408051601f6000199c841615610100029c909c0190921698909804998a018d90048d0281018d019097528887526001600160a01b039099169b50959993989297919690959492938301828280156125135780601f106124e857610100808354040283529160200191612513565b820191906000526020600020905b8154815290600101906020018083116124f657829003601f168201915b5050505050905088565b600054610100900460ff16806125365750612536614095565b80612544575060005460ff16155b6125605760405162461bcd60e51b815260040161052490615a75565b600054610100900460ff1615801561258b576000805460ff1961ff0019909116610100171660011790555b6125948261409b565b80156107a6576000805461ff00191690555050565b60008181526065602052604081206104f190614125565b6000828152606560205260409020600201546125de906103ff6138d7565b6118835760405162461bcd60e51b81526004016105249061576a565b6001600160a01b03166000908152609a602052604090205490565b6000611cc98383612624612c74565b614130565b60006104f161263783611c50565b61264084613479565b9063ffffffff61416b16565b60006126588133611cd2565b90505b90565b60606104f18260006129b4565b600082600301546000141561268257506000611ccc565b8183600301541161279b5760038301545b8281116127835760008181526001808601602090815260408084205491889052832054612700926126f4919060028a019086906126d790899063ffffffff61419016565b81526020019081526020016000205461416b90919063ffffffff16565b9063ffffffff6141d216565b6000838152600287016020526040902054909150811461272e57600082815260028601602052604090208190555b60008281526020869052604090205415612752576000828152602086905260408120555b60008281526001860160205260409020541561277a5760008281526001860160205260408120555b50600101612693565b5061279582600163ffffffff61416b16565b60038401555b506000908152600291909101602052604090205490565b609754604051633581777360e01b81526000916001600160a01b0316906335817773906127e19060040161546c565b60206040518083038186803b1580156127f957600080fd5b505afa15801561280d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128319190615062565b9050600080805b845181101561294657826001600160a01b031685828151811061285757fe5b6020026020010151600001516001600160a01b0316146129115781156128d857604051634458328b60e01b81526001600160a01b03851690634458328b906128a59086908690600401615264565b600060405180830381600087803b1580156128bf57600080fd5b505af11580156128d3573d6000803e3d6000fd5b505050505b8481815181106128e457fe5b60200260200101516000015192508481815181106128fe57fe5b602002602001015160200151915061293e565b61293b85828151811061292057fe5b6020026020010151602001518361416b90919063ffffffff16565b91505b600101612838565b5080156129ae57604051634458328b60e01b81526001600160a01b03841690634458328b9061297b9085908590600401615264565b600060405180830381600087803b15801561299557600080fd5b505af11580156129a9573d6000803e3d6000fd5b505050505b50505050565b60606129bf83611816565b15611ccc576001600160a01b038316600090815260a3602052604090205460a25483158015906129fd5750806129fb838663ffffffff61416b16565b105b15612a1557612a12828563ffffffff61416b16565b90505b612a25818363ffffffff61419016565b67ffffffffffffffff81118015612a3b57600080fd5b50604051908082528060200260200182016040528015612a7557816020015b612a62614f97565b815260200190600190039081612a5a5790505b509250815b81831015612c5357600060a28481548110612a9157fe5b9060005260206000209060040201600201549050600060a28581548110612ab457fe5b90600052602060002090600402016003015490506000612ad5898484614130565b9050612ae881600063ffffffff61422516565b15612c45576001600160a01b0389166000908152609f6020526040902060a28054612b6a92919089908110612b1957fe5b6000918252602080832060408051808201825260049094029091018054845260010154838301526001600160a01b038f16845260a0825280842089855290915290912091908563ffffffff61423e16565b612bca60a28781548110612b7a57fe5b6000918252602080832060408051808201825260049094029091018054845260010154838301526001600160a01b038e16845260a18252808420888552909152909120908463ffffffff612e4216565b8887612bdc888763ffffffff61419016565b81518110612be657fe5b60209081029190910101516001600160a01b039091169052612c19612c0c8a8585614130565b829063ffffffff6141d216565b87612c2a888763ffffffff61419016565b81518110612c3457fe5b602002602001015160200181815250505b505050826001019250612a7a565b506001600160a01b038516600090815260a360205260409020555092915050565b609754604051633581777360e01b815260009182916001600160a01b0390911690633581777390612ca79060040161565f565b60206040518083038186803b158015612cbf57600080fd5b505afa158015612cd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf79190615062565b9050806001600160a01b031663ddd1b67e6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d3257600080fd5b505afa158015612d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6a9190615165565b91505090565b612d78614f7d565b6003840154612d8e83600163ffffffff61416b16565b1015612dac5760405162461bcd60e51b815260040161052490615435565b6003840154612dc657612dbf600061424c565b9050612e3b565b6000612dd28584613ac3565b9050612de581600063ffffffff61425f16565b15612dfc57612df4600061424c565b915050612e3b565b8380821015612e085750805b612e10614f7d565b612e29612e23848463ffffffff6141d216565b84614285565b9050612e368782876142d5565b925050505b9392505050565b6003830154612e5882600163ffffffff61416b16565b1015612e765760405162461bcd60e51b815260040161052490615733565b602082015182511115612e9b5760405162461bcd60e51b81526004016105249061548e565b6003830154612ea957612f8d565b6000612eb5848361266b565b9050612ec881600063ffffffff61425f16565b15612ed35750612f8d565b6020808401518451600085815260028801909352604090922054612f0d92612f01919063ffffffff61384a16565b9063ffffffff6142e316565b6000838152600286016020526040812091909155612f3283600163ffffffff61416b16565b90505b84600401548111612f8a576020808501518551600084815260018901909352604090922054612f6e92612f01919063ffffffff61384a16565b6000828152600180880160205260409091209190915501612f35565b50505b505050565b6001830154612fd057600180840182905560028085018390556000838152602086815260408220865181559086015193810193909355910155612f8d565b8083600201541115612ff45760405162461bcd60e51b815260040161052490615a30565b808360020154141561305557600081815260208481526040918290208251808401909352805483526001015490820152613034908363ffffffff61432516565b60008281526020858152604090912082518155910151600190910155612f8d565b60008181526020848152604080832085518155918501516001830155600291820183905581860180548452922001829055819055505050565b609754604051633581777360e01b815260009182916001600160a01b03909116906335817773906130c19060040161557a565b60206040518083038186803b1580156130d957600080fd5b505afa1580156130ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131119190615062565b6001600160a01b038516600090815260a6602090815260408083208784526001019091529020549091501515806131fe57506001600160a01b038416600090815260a6602090815260408083208684526001019091529020541580156131fe5750806001600160a01b031663049e41776040518163ffffffff1660e01b815260040160206040518083038186803b1580156131ab57600080fd5b505afa1580156131bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e39190615165565b6001600160a01b038516600090815260a66020526040902054105b6119c35760405162461bcd60e51b815260040161052490615d77565b6098805460408051610100810182526001600160a01b03898116825260208083018a8152938301898152606084018981524260808601908152600060a0870181815260c0880182815260e089018d815260018c018d559b90925287517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81460088c0290810180546001600160a01b0319169290991691909117885598517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d8158a015593517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81689015591517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d817880155517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81887015590517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d819860155517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81a850155945180519495929491936133d1937f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81b90910192910190614fae565b5050506000858152609960209081526040808320805460018181018355918552838520018590556001600160a01b038a168452609a83529083208054918201815583529120018190556098805461346f91908390811061342d57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918490811061345857fe5b906000526020600020906008020160020154614363565b5095945050505050565b600080613484612c74565b905061348f83611c42565b6001600160a01b0383166000908152609f60205260409020612e3b908263ffffffff613ac316565b6001600160a01b038216600090815260a660209081526040808320848452600190810190925290912054141561352b576001600160a01b038216600090815260a6602052604090205461351190600163ffffffff61419016565b6001600160a01b038316600090815260a660205260409020555b6001600160a01b038216600090815260a6602090815260408083208484526001908101909252909120546135649163ffffffff61419016565b6001600160a01b03909216600090815260a660209081526040808320938352600190930190522055565b600080613599612c74565b90506000609884815481106135aa57fe5b906000526020600020906008020160050154905080821015613600576135f7609885815481106135d657fe5b9060005260206000209060080201600301548261416b90919063ffffffff16565b925050506104f4565b60006136376098868154811061361257fe5b906000526020600020906008020160030154612f01848661419090919063ffffffff16565b905061368b61367e6098878154811061364c57fe5b90600052602060002090600802016003015461367260018561416b90919063ffffffff16565b9063ffffffff61384a16565b839063ffffffff61416b16565b93505050506104f4565b6000818152609b602052604081205460988054839190859081106136b557fe5b90600052602060002090600802016001015490506000609885815481106136d857fe5b90600052602060002090600802016002015490508260001415613718576000828152609e60205260409020600101549250826137185792506104f4915050565b825b60008111801561374757506098868154811061373257fe5b90600052602060002090600802016006015481105b156137c5576098868154811061375957fe5b90600052602060002090600802016005015481106137a4576000838152609e602090815260408083208484529091529020600181015490546137a19190612f0190859061384a565b91505b6000838152609e60209081526040808320938352929052206002015461371a565b50949350505050565b6000838152609c60205260409020612f8d90838363ffffffff61440716565b6001600160a01b0383166000908152609f60205260409020612f8d90838363ffffffff61440716565b6001600160a01b038416600090815260a06020908152604080832086845290915290206129ae90838363ffffffff61440716565b60008261385957506000611ccc565b8282028284828161386657fe5b0414611cc95760405162461bcd60e51b815260040161052490615920565b6000838152609d60205260409020612f8d90838363ffffffff6144c816565b6001600160a01b038416600090815260a16020908152604080832086845290915290206129ae90838363ffffffff6144c816565b3390565b60008281526065602052604090206138f9908263ffffffff61454616565b156107a6576139066138d7565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0316600090815260a46020526040902054151590565b6000828152606560205260409020613985908263ffffffff61455b16565b156107a6576139926138d7565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b6000611cc98383614570565b6000611cc9836001600160a01b0384166145b5565b600080613a02612c74565b6001600160a01b038516600090815260a560205260409020600101549091508114613a3f5760405162461bcd60e51b8152600401610524906157f1565b6001600160a01b038416600090815260a56020526040902054831115613a775760405162461bcd60e51b815260040161052490615895565b6001600160a01b038416600090815260a56020526040902054613aa0908463ffffffff61419016565b6001600160a01b03909416600090815260a5602052604090209390935592915050565b6003820154600090613adc83600163ffffffff61416b16565b1015613afa5760405162461bcd60e51b8152600401610524906156af565b6003830154613b0b57506000611ccc565b81836003015411613bda5760038301545b828111613bc2576000818152600185016020908152604080832054918790528220546002870154613b5892916126f4919063ffffffff61416b16565b905080856002015414613b6d57600285018190555b60008281526020869052604090205415613b91576000828152602086905260408120555b600082815260018601602052604090205415613bb95760008281526001860160205260408120555b50600101613b1c565b50613bd482600163ffffffff61416b16565b60038401555b50506002015490565b609754604051633581777360e01b81526000916001600160a01b031690633581777390613c12906004016159f9565b60206040518083038186803b158015613c2a57600080fd5b505afa158015613c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c629190615062565b90506000613c6e612c74565b9050613c8181600163ffffffff61416b16565b60988481548110613c8e57fe5b9060005260206000209060080201600501819055506000609e600060988681548110613cb657fe5b9060005260206000209060080201600101548152602001908152602001600020600201541115613d2757609e600060988581548110613cf157fe5b60009182526020808320600160089093020191909101548352828101939093526040918201812060020154868252609b90935220555b613d8160988481548110613d3757fe5b90600052602060002090600802016001015460988581548110613d5657fe5b906000526020600020906008020160020154613d7c60018561416b90919063ffffffff16565b6145cd565b613de760988481548110613d9157fe5b6000918252602090912060089091020154609880546001600160a01b039092169186908110613dbc57fe5b906000526020600020906008020160020154613de260018561416b90919063ffffffff16565b6145ec565b613e6c60988481548110613df757fe5b6000918252602090912060089091020154609880546001600160a01b039092169186908110613e2257fe5b90600052602060002090600802016001015460988681548110613e4157fe5b906000526020600020906008020160020154613e6760018661416b90919063ffffffff16565b614615565b613ed260988481548110613e7c57fe5b6000918252602090912060089091020154609880546001600160a01b039092169186908110613ea757fe5b906000526020600020906008020160010154613ecd60018561416b90919063ffffffff16565b614649565b6000613f9e836001600160a01b031663f5b98f4160988781548110613ef357fe5b9060005260206000209060080201600301546040518263ffffffff1660e01b8152600401613f219190615324565b60206040518083038186803b158015613f3957600080fd5b505afa158015613f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f719190615165565b60988681548110613f7e57fe5b90600052602060002090600802016002015461384a90919063ffffffff16565b9050613fdc60988581548110613fb057fe5b90600052602060002090600802016001015482613fd760018661416b90919063ffffffff16565b6146e7565b61404360988581548110613fec57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918790811061401757fe5b9060005260206000209060080201600101548361403e60018761416b90919063ffffffff16565b614706565b6129ae6098858154811061405357fe5b6000918252602090912060089091020154609880546001600160a01b03909216918790811061407e57fe5b90600052602060002090600802016001015461473a565b303b1590565b600054610100900460ff16806140b457506140b4614095565b806140c2575060005460ff16155b6140de5760405162461bcd60e51b815260040161052490615a75565b600054610100900460ff16158015614109576000805460ff1961ff0019909116610100171660011790555b6141116147e2565b61411c60003361180c565b61259482614874565b60006104f1826148ea565b6001600160a01b038316600090815260a0602090815260408083208584529091528120614163908363ffffffff613ac316565b949350505050565b600082820183811015611cc95760405162461bcd60e51b8152600401610524906155f8565b6000611cc983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506148ee565b60008183106141e45750808203611ccc565b7f5b70a077a991facb623c7b2ee44cc539dc6ba345b6636552b8ea97fbbd4d54198383604051614215929190615e94565b60405180910390a1506000611ccc565b6000620f424019821061423457fe5b50620f4240011090565b6129ae84848484600161491a565b614254614f7d565b6104f1826001614285565b6000818311156142775750620f424081830310611ccc565b50620f424082820310611ccc565b61428d614f7d565b600082116142ad5760405162461bcd60e51b815260040161052490615998565b6142b5614f7d565b6040518060400160405280858152602001848152509050611cc981614b01565b612f8d83848484600061491a565b6000611cc983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614b4d565b61432d614f7d565b81518351611cc991614345919063ffffffff61384a16565b6020808501519086015161435e9163ffffffff61384a16565b614285565b60008061436e612c74565b6001600160a01b038516600090815260a560205260409020600101549091508111156143ba576001600160a01b038416600090815260a5602052604090208381556001018190556119c3565b6001600160a01b038416600090815260a5602052604090206001015481146143de57fe5b6001600160a01b038416600090815260a56020526040902054613aa0908463ffffffff61416b16565b61441881600163ffffffff61416b16565b8360030154111561443b5760405162461bcd60e51b8152600401610524906159c2565b60038301546144535760038301819055600483018190555b826004015481111561446757600483018190555b826003015481106144a9576000818152600184016020526040902054614493908363ffffffff61416b16565b6000828152600185016020526040902055612f8d565b60028301546144be908363ffffffff6141d216565b6002840155505050565b80836003015411156144ec5760405162461bcd60e51b8152600401610524906159c2565b60038301546144fd57600383018190555b600081815260018401602052604090205461451e908363ffffffff61416b16565b600082815260018501602052604090205560048301548114612f8d5760048301819055505050565b6000611cc9836001600160a01b038416614b84565b6000611cc9836001600160a01b038416614bce565b815460009082106145935760405162461bcd60e51b8152600401610524906153a4565b8260000182815481106145a257fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b6000838152609c60205260409020612f8d90838363ffffffff614c9416565b6001600160a01b0383166000908152609f60205260409020612f8d90838363ffffffff614c9416565b6001600160a01b038416600090815260a06020908152604080832086845290915290206129ae90838363ffffffff614c9416565b6001600160a01b038316600090815260a46020526040902054614691576001600160a01b038316600090815260a46020908152604080832084905560a25460a3909252909120555b6001600160a01b038316600090815260a460209081526040808320858452600101909152902054612f8d576001600160a01b0392909216600090815260a460209081526040808320938352600190930190522055565b6000838152609d60205260409020612f8d90838363ffffffff614d3716565b6001600160a01b038416600090815260a16020908152604080832086845290915290206129ae90838363ffffffff614d3716565b6001600160a01b038216600090815260a6602090815260408083208484526001019091529020546147a9576001600160a01b038216600090815260a6602052604090205461478f90600163ffffffff61416b16565b6001600160a01b038316600090815260a660205260409020555b6001600160a01b038216600090815260a6602090815260408083208484526001908101909252909120546135649163ffffffff61416b16565b600054610100900460ff16806147fb57506147fb614095565b80614809575060005460ff16155b6148255760405162461bcd60e51b815260040161052490615a75565b600054610100900460ff16158015614850576000805460ff1961ff0019909116610100171660011790555b614858614db1565b614860614db1565b8015611c4d576000805461ff001916905550565b6001600160a01b03811661489a5760405162461bcd60e51b815260040161052490615ae7565b6148ac816001600160a01b0316614e32565b6148c85760405162461bcd60e51b815260040161052490615961565b609780546001600160a01b0319166001600160a01b0392909216919091179055565b5490565b600081848411156149125760405162461bcd60e51b81526004016105249190615341565b505050900390565b600385015461493083600163ffffffff61416b16565b101561494e5760405162461bcd60e51b815260040161052490615435565b801561498857600384015461496a83600163ffffffff61416b16565b10156149885760405162461bcd60e51b815260040161052490615435565b6020830151835111156149ad5760405162461bcd60e51b81526004016105249061548e565b60038501546149bb57612f8a565b60006149c78684613ac3565b90506149da81600063ffffffff61425f16565b156149e55750612f8a565b6000614a0a8560200151612f0187600001518a6002015461384a90919063ffffffff16565b90508215614a3357614a3386614a2d838a600201546141d290919063ffffffff16565b86614407565b600287018190556000614a4d85600163ffffffff61416b16565b90505b876004015481116129a9576020808701518751600084815260018c019093526040832054614a899291612f01919063ffffffff61384a16565b90508415614ae557600082815260018a016020526040902054614ad390614ab6908363ffffffff6141d216565b600084815260018b0160205260409020549063ffffffff6141d216565b600083815260018a0160205260409020555b60008281526001808b0160205260409091209190915501614a50565b6000614b1582600001518360200151614e6b565b8251909150614b2a908263ffffffff6142e316565b82526020820151614b41908263ffffffff6142e316565b60209092019190915250565b60008183614b6e5760405162461bcd60e51b81526004016105249190615341565b506000838581614b7a57fe5b0495945050505050565b6000614b9083836145b5565b614bc657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ccc565b506000611ccc565b60008181526001830160205260408120548015614c8a5783546000198083019190810190600090879083908110614c0157fe5b9060005260206000200154905080876000018481548110614c1e57fe5b600091825260208083209091019290925582815260018981019092526040902090840190558654879080614c4e57fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611ccc565b6000915050611ccc565b8083600301541115614cb85760405162461bcd60e51b81526004016105249061562f565b6003830154614cd05760038301819055600483018190555b8260040154811115614ce457600483018190555b82600301548110614d2257600081815260208490526040902054614d0e908363ffffffff61416b16565b600082815260208590526040902055612f8d565b60028301546144be908363ffffffff61416b16565b8083600301541115614d5b5760405162461bcd60e51b81526004016105249061562f565b6003830154614d6c57600383018190555b600081815260208490526040902054614d8b908363ffffffff61416b16565b60008281526020859052604090205560048301548114612f8d5760048301819055505050565b600054610100900460ff1680614dca5750614dca614095565b80614dd8575060005460ff16155b614df45760405162461bcd60e51b815260040161052490615a75565b600054610100900460ff16158015614860576000805460ff1961ff0019909116610100171660011790558015611c4d576000805461ff001916905550565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590614163575050151592915050565b6000828281811115614e8757614e818282614ebb565b90925090505b8015614eb357614e9d828263ffffffff614ebe16565b9150614ea98282614ebb565b9092509050614e87565b509392505050565b91565b6000611cc983836040518060400160405280601881526020017f536166654d6174683a206d6f64756c6f206279207a65726f000000000000000081525060008183614f1c5760405162461bcd60e51b81526004016105249190615341565b50828481614f2657fe5b06949350505050565b60405180610100016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081525090565b604051806040016040528060008152602001600081525090565b604080518082019091526000808252602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614fef57805160ff191683800117855561501c565b8280016001018555821561501c579182015b8281111561501c578251825591602001919060010190615001565b5061502892915061502c565b5090565b61265b91905b808211156150285760008155600101615032565b600060208284031215615057578081fd5b8135611cc981615ece565b600060208284031215615073578081fd5b8151611cc981615ece565b60008060408385031215615090578081fd5b823561509b81615ece565b946020939093013593505050565b6000806000606084860312156150bd578081fd5b83356150c881615ece565b95602085013595506040909401359392505050565b6000602082840312156150ee578081fd5b81518015158114611cc9578182fd5b60006020828403121561510e578081fd5b5035919050565b60008060408385031215615127578182fd5b82359150602083013561513981615ece565b809150509250929050565b60008060408385031215615156578182fd5b50508035926020909101359150565b600060208284031215615176578081fd5b5051919050565b600080600080600060808688031215615194578081fd5b853594506020860135935060408601359250606086013567ffffffffffffffff808211156151c0578283fd5b81880189601f8201126151d1578384fd5b80359250818311156151e1578384fd5b8960208483010111156151f2578384fd5b6020810194505050809150509295509295909350565b60008151808452615220816020860160208601615ea2565b601f01601f19169290920160200192915050565b60008251615246818460208701615ea2565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b600061010060018060a01b038b1683528960208401528860408401528760608401528660808401528560a08401528460c08401528060e084015261530a81840185615208565b9b9a5050505050505050505050565b901515815260200190565b90815260200190565b602081016007831061533b57fe5b91905290565b600060208252611cc96020830184615208565b60208082526030908201527f4f6e6c7920746f6b656e20686f6c646572732063616e2063616e63656c20646560408201526f1b1959d85d1a5bdb881c995c5d595cdd60821b606082015260800190565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252602f908201527f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60408201526e0818591b5a5b881d1bc819dc985b9d608a1b606082015260800190565b6020808252601f908201527f43616e6e6f74207265647563652076616c756520696e20746865207061737400604082015260600190565b602080825260089082015267283ab734b9b432b960c11b604082015260600190565b60208082526027908201527f496e6372656173696e67206f662076616c756573206973206e6f7420696d706c604082015266195b595b9d195960ca1b606082015260800190565b60208082526028908201527f5468652064656c65676174696f6e20686173206265656e20616c7265616479206040820152671858d8d95c1d195960c21b606082015260800190565b60208082526038908201527f56616c696461746f72206973206e6f7420617574686f72697a656420746f206160408201527f63636570742064656c65676174696f6e20726571756573740000000000000000606082015260800190565b6020808252600f908201526e21b7b739ba30b73a39a437b63232b960891b604082015260600190565b60208082526035908201527f5468652076616c696461746f72206973206e6f742063757272656e746c7920616040820152746363657074696e67206e657720726571756573747360581b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526016908201527510d85b9b9bdd08185919081d1bc81d1a19481c185cdd60521b604082015260600190565b6020808252600b908201526a54696d6548656c7065727360a81b604082015260600190565b6020808252601190820152702a37b5b2b72630bab731b42637b1b5b2b960791b604082015260600190565b60208082526022908201527f43616e6e6f742063616c63756c6174652076616c756520696e207468652070616040820152611cdd60f21b606082015260800190565b60208082526022908201527f5468652064656c65676174696f6e2072657175657374206973206f7574646174604082015261195960f21b606082015260800190565b6020808252601e908201527f43616e2774207265647563652076616c756520696e2074686520706173740000604082015260600190565b60208082526030908201527f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60408201526f2061646d696e20746f207265766f6b6560801b606082015260800190565b6020808252601b908201527f43616e6e6f74207265717565737420756e64656c65676174696f6e0000000000604082015260600190565b6020808252602b908201527f546865726520617265206e6f2064656c65676174696f6e20726571756573747360408201526a040e8d0d2e640dadedce8d60ab1b606082015260800190565b6020808252818101527f4e6f207065726d697373696f6e7320746f206163636570742072657175657374604082015260600190565b6020808252600a908201526929b5b0b632aa37b5b2b760b11b604082015260600190565b6020808252601b908201527f556e6c6f636b696e6720616d6f756e7420697320746f6f206269670000000000604082015260600190565b60208082526034908201527f546f6b656e20686f6c64657220646f6573206e6f74206861766520656e6f75676040820152736820746f6b656e7320746f2064656c656761746560601b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527f41646472657373206973206e6f7420636f6e7472616374000000000000000000604082015260600190565b60208082526010908201526f4469766973696f6e206279207a65726f60801b604082015260600190565b6020808252601d908201527f43616e6e6f742073756274726163742066726f6d207468652070617374000000604082015260600190565b60208082526017908201527f44656c65676174696f6e506572696f644d616e61676572000000000000000000604082015260600190565b60208082526025908201527f43616e6e6f742070757420736c617368696e67206576656e7420696e20746865604082015264081c185cdd60da1b606082015260800190565b6020808252602e908201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560408201526d195b881a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252600a9082015269546f6b656e537461746560b01b604082015260600190565b60208082526022908201527f436f6e74726163744d616e616765722061646472657373206973206e6f742073604082015261195d60f21b606082015260800190565b6020808252603a908201527f546f6b656e20686f6c6465727320617265206f6e6c792061626c6520746f206360408201527f616e63656c2050524f504f5345442064656c65676174696f6e73000000000000606082015260800190565b60208082526027908201527f43616e6e6f74207365742064656c65676174696f6e20737461746520746f206160408201526618d8d95c1d195960ca1b606082015260800190565b60208082526025908201527f546869732064656c65676174696f6e20706572696f64206973206e6f7420616c6040820152641b1bddd95960da1b606082015260800190565b6020808252603e908201527f416d6f756e7420646f6573206e6f74206d656574207468652076616c6964617460408201527f6f722773206d696e696d756d2064656c65676174696f6e20616d6f756e740000606082015260800190565b60208082526031908201527f5468652064656c65676174696f6e20686173206265656e2063616e63656c6c656040820152703210313c903a37b5b2b7103437b63232b960791b606082015260800190565b60208082526019908201527f44656c65676174696f6e20646f6573206e6f7420657869737400000000000000604082015260600190565b60208082526029908201527f5065726d697373696f6e2064656e69656420746f207265717565737420756e6460408201526832b632b3b0ba34b7b760b91b606082015260800190565b60208082526019908201527f4d6573736167652073656e64657220697320696e76616c696400000000000000604082015260600190565b6020808252601e908201527f4c696d6974206f662076616c696461746f727320697320726561636865640000604082015260600190565b60208082526010908201526f56616c696461746f725365727669636560801b604082015260600190565b6020808252602f908201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560408201526e103937b632b9903337b91039b2b63360891b606082015260800190565b60006020825260018060a01b038351166020830152602083015160408301526040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e08301516101008081850152506119c0610120840182615208565b918252602082015260400190565b60005b83811015615ebd578181015183820152602001615ea5565b838111156129ae5750506000910152565b6001600160a01b0381168114611c4d57600080fdfea264697066735822122088c330383e3eca2d1dd22b553b5b109eafd04aa92a00d266c363bddb03bdaf0064736f6c634300060a0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102115760003560e01c806356574b8c11610125578063b39e12cf116100ad578063ca15c8731161007c578063ca15c8731461049a578063d547741f146104ad578063dda641ae146104c0578063fa8dacba14610216578063ff1f7799146104d357610211565b8063b39e12cf14610445578063b86315851461044d578063c4336c1c14610460578063c4d66de81461048757610211565b806391d14854116100f457806391d14854146103f15780639654ff16146104045780639ac1c4ad146104175780639c3e452f1461042a578063a217fddf1461043d57610211565b806356574b8c146103985780635fd55293146103ab5780637ce845d0146103be5780639010d07c146103d157610211565b8063248a9ca3116101a85780632f7263cd116101775780632f7263cd1461031f57806336568abe1461033f5780633d42b1ce14610352578063416880b01461036557806344c9af281461037857610211565b8063248a9ca3146102d357806327040f68146102e657806327e5455a146102f95780632f2ff15d1461030c57610211565b80631d703812116101e45780631d703812146102875780631d9c7f0a1461029a5780631da42e5e146102ad57806321eb5859146102c057610211565b80630b975991146102165780630dd357011461023f5780630e01bff81461025f5780631c8a253e14610272575b600080fd5b610229610224366004615046565b6104e6565b6040516102369190615324565b60405180910390f35b61025261024d3660046150fd565b6104f9565b6040516102369190615e27565b61022961026d3660046150a9565b61063c565b61028561028036600461507e565b610794565b005b6102296102953660046150fd565b6107aa565b6102296102a8366004615144565b6107b8565b6102856102bb366004615144565b6107e6565b6102856102ce36600461517d565b610a25565b6102296102e13660046150fd565b611065565b6102296102f4366004615046565b61107a565b6102856103073660046150fd565b611085565b61028561031a366004615115565b6117d2565b61033261032d366004615046565b611816565b6040516102369190615319565b61028561034d366004615115565b61184b565b6102296103603660046150fd565b61188d565b610229610373366004615144565b61189f565b61038b6103863660046150fd565b6119ca565b604051610236919061532d565b6102296103a636600461507e565b611c29565b6102856103b9366004615046565b611c42565b6102296103cc366004615046565b611c50565b6103e46103df366004615144565b611cab565b6040516102369190615250565b6103326103ff366004615115565b611cd2565b61022961041236600461507e565b611cf0565b6102856104253660046150fd565b611d1c565b610229610438366004615144565b611e6f565b610229611f8a565b6103e4611f8f565b61028561045b3660046150fd565b611f9e565b61047361046e3660046150fd565b612434565b6040516102369897969594939291906152c4565b610285610495366004615046565b61251d565b6102296104a83660046150fd565b6125a9565b6102856104bb366004615115565b6125c0565b6102296104ce366004615046565b6125fa565b6102296104e136600461507e565b612615565b60006104f182612629565b90505b919050565b610501614f2f565b6098548290811061052d5760405162461bcd60e51b815260040161052490615cc0565b60405180910390fd5b6098838154811061053a57fe5b600091825260209182902060408051610100808201835260089490940290920180546001600160a01b0316835260018082015484870152600280830154858501526003830154606086015260048301546080860152600583015460a0860152600683015460c08601526007830180548551938116159097026000190190961604601f81018790048702820187019093528281529294909360e086019392909183018282801561062a5780601f106105ff5761010080835404028352916020019161062a565b820191906000526020600020905b81548152906001019060200180831161060d57829003601f168201915b50505050508152505091505b50919050565b604080518082018252600b81526a2234b9ba3934b13aba37b960a91b602080830191909152609754925160009333926001600160a01b039091169163ec56a3739161068991869101615234565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004016106bb9190615324565b60206040518083038186803b1580156106d357600080fd5b505afa1580156106e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070b9190615062565b6001600160a01b03161480610723575061072361264c565b61073f5760405162461bcd60e51b815260040161052490615d40565b606061074a8661265e565b6001600160a01b038716600090815260a1602090815260408083208984529091529020909150610780908563ffffffff61266b16565b925061078b816127b2565b50509392505050565b6107a66107a183836129b4565b6127b2565b5050565b60006104f182610438612c74565b609960205281600052604060002081815481106107d157fe5b90600052602060002001600091509150505481565b6040805180820182526008815267283ab734b9b432b960c11b6020808301919091526097549251919233926001600160a01b039091169163ec56a3739161082f91869101615234565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004016108619190615324565b60206040518083038186803b15801561087957600080fd5b505afa15801561088d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b19190615062565b6001600160a01b031614806108c957506108c961264c565b6108e55760405162461bcd60e51b815260040161052490615d40565b60006108ef612c74565b90506108f9614f7d565b6000858152609c6020526040902061091890858463ffffffff612d7016565b6000868152609d6020526040902090915061093a90828463ffffffff612e4216565b6000858152609e60205260409020610953908284612f92565b60408051606081018252918252602080830196875290820192835260a28054600181018255600091909152915180517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42d60049094029384015501517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42e82015593517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42f850155517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf430909301929092555050565b609754604051633581777360e01b81526000916001600160a01b031690633581777390610a5490600401615dae565b60206040518083038186803b158015610a6c57600080fd5b505afa158015610a80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa49190615062565b609754604051633581777360e01b81529192506000916001600160a01b0390911690633581777390610ad8906004016159f9565b60206040518083038186803b158015610af057600080fd5b505afa158015610b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b289190615062565b609754604051633581777360e01b81529192506000916001600160a01b0390911690633581777390610b5c90600401615871565b60206040518083038186803b158015610b7457600080fd5b505afa158015610b88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bac9190615062565b609754604051633581777360e01b81529192506000916001600160a01b0390911690633581777390610be090600401615ac3565b60206040518083038186803b158015610bf857600080fd5b505afa158015610c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c309190615062565b6040516370cb318960e01b81529091506001600160a01b038516906370cb318990610c61908c908c90600401615e94565b60206040518083038186803b158015610c7957600080fd5b505afa158015610c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb191906150dd565b610ccd5760405162461bcd60e51b815260040161052490615c12565b60405163f93c86f160e01b81526001600160a01b0385169063f93c86f190610cf9908c90600401615324565b60206040518083038186803b158015610d1157600080fd5b505afa158015610d25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4991906150dd565b610d655760405162461bcd60e51b81526004016105249061551d565b60405163a795d29360e01b81526001600160a01b0384169063a795d29390610d91908a90600401615324565b60206040518083038186803b158015610da957600080fd5b505afa158015610dbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de191906150dd565b610dfd5760405162461bcd60e51b815260040161052490615bcd565b60405163461a6f3f60e11b81526001600160a01b03851690638c34de7e90610e29908c90600401615324565b60206040518083038186803b158015610e4157600080fd5b505afa158015610e55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7991906150dd565b610e955760405162461bcd60e51b8152600401610524906155a3565b610e9f338a61308e565b506060610eab3361265e565b90506000610ef2338c8c8c8c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061321a92505050565b90506000846001600160a01b03166370a08231336040518263ffffffff1660e01b8152600401610f229190615250565b60206040518083038186803b158015610f3a57600080fd5b505afa158015610f4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f729190615165565b90506000846001600160a01b0316630b975991336040518263ffffffff1660e01b8152600401610fa29190615250565b602060405180830381600087803b158015610fbc57600080fd5b505af1158015610fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff49190615165565b9050808210156110165760405162461bcd60e51b8152600401610524906158cc565b7f839237f8da6208af7e49773f22501b3082aaae94d5b6ce8ee96f117835fe2f67836040516110459190615324565b60405180910390a1611056846127b2565b50505050505050505050505050565b60009081526065602052604090206002015490565b60006104f182613479565b609854819081106110a85760405162461bcd60e51b815260040161052490615cc0565b60046110b3836119ca565b60068111156110be57fe5b146110db5760405162461bcd60e51b8152600401610524906157ba565b609754604051633581777360e01b81526000916001600160a01b03169063358177739061110a90600401615dae565b60206040518083038186803b15801561112257600080fd5b505afa158015611136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115a9190615062565b9050336001600160a01b03166098848154811061117357fe5b60009182526020909120600890910201546001600160a01b031614806112b357506040516224441f60e71b81526001600160a01b038216906312220f80906111bf903390600401615250565b60206040518083038186803b1580156111d757600080fd5b505afa1580156111eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120f91906150dd565b80156112b35750604051630ba7341960e11b81526001600160a01b0382169063174e683290611242903390600401615250565b60206040518083038186803b15801561125a57600080fd5b505afa15801561126e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112929190615165565b6098848154811061129f57fe5b906000526020600020906008020160010154145b6112cf5760405162461bcd60e51b815260040161052490615cf7565b609754604051633581777360e01b81526000916001600160a01b0316906335817773906112fe90600401615684565b60206040518083038186803b15801561131657600080fd5b505afa15801561132a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134e9190615062565b609754604051633581777360e01b81529192506000916001600160a01b0390911690633581777390611382906004016159f9565b60206040518083038186803b15801561139a57600080fd5b505afa1580156113ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d29190615062565b9050611426609886815481106113e457fe5b6000918252602090912060089091020154609880546001600160a01b03909216918890811061140f57fe5b9060005260206000209060080201600101546134b7565b61142f33611c42565b6114388561358e565b6098868154811061144557fe5b906000526020600020906008020160060181905550600061146586613695565b90506114ae6098878154811061147757fe5b906000526020600020906008020160010154826098898154811061149757fe5b9060005260206000209060080201600601546137ce565b611508609887815481106114be57fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b031682609889815481106114f157fe5b9060005260206000209060080201600601546137ed565b61157a6098878154811061151857fe5b6000918252602090912060089091020154609880546001600160a01b03909216918990811061154357fe5b9060005260206000209060080201600101548360988a8154811061156357fe5b906000526020600020906008020160060154613816565b6000611626836001600160a01b031663f5b98f4160988a8154811061159b57fe5b9060005260206000209060080201600301546040518263ffffffff1660e01b81526004016115c99190615324565b60206040518083038186803b1580156115e157600080fd5b505afa1580156115f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116199190615165565b839063ffffffff61384a16565b905061166f6098888154811061163857fe5b9060005260206000209060080201600101548260988a8154811061165857fe5b906000526020600020906008020160060154613884565b6116e16098888154811061167f57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918a9081106116aa57fe5b9060005260206000209060080201600101548360988b815481106116ca57fe5b9060005260206000209060080201600601546138a3565b836001600160a01b0316630d4e8fd1609889815481106116fd57fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b03168960988b8154811061173057fe5b9060005260206000209060080201600601546040518463ffffffff1660e01b81526004016117609392919061527d565b600060405180830381600087803b15801561177a57600080fd5b505af115801561178e573d6000803e3d6000fd5b505050507fb0142de902382ce87e0ae1e5ec0699b26d25bec2eeb06bca82e1253099b3119c876040516117c19190615324565b60405180910390a150505050505050565b6000828152606560205260409020600201546117f0906103ff6138d7565b61180c5760405162461bcd60e51b8152600401610524906153e6565b6107a682826138db565b60006118218261394a565b80156104f157505060a2546001600160a01b0391909116600090815260a360205260409020541090565b6118536138d7565b6001600160a01b0316816001600160a01b0316146118835760405162461bcd60e51b815260040161052490615dd8565b6107a68282613967565b60009081526099602052604090205490565b604080518082018252600b81526a2234b9ba3934b13aba37b960a91b602080830191909152609754925160009333926001600160a01b039091169163ec56a373916118ec91869101615234565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b815260040161191e9190615324565b60206040518083038186803b15801561193657600080fd5b505afa15801561194a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196e9190615062565b6001600160a01b03161480611986575061198661264c565b6119a25760405162461bcd60e51b815260040161052490615d40565b6000848152609d602052604090206119c0908463ffffffff61266b16565b91505b5092915050565b609854600090829081106119f05760405162461bcd60e51b815260040161052490615cc0565b609883815481106119fd57fe5b90600052602060002090600802016005015460001415611b845760988381548110611a2457fe5b90600052602060002090600802016006015460001415611b7b57609754604051633581777360e01b81526000916001600160a01b031690633581777390611a6d9060040161565f565b60206040518083038186803b158015611a8557600080fd5b505afa158015611a99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abd9190615062565b9050806001600160a01b031663bf64d84960988681548110611adb57fe5b9060005260206000209060080201600401546040518263ffffffff1660e01b8152600401611b099190615324565b60206040518083038186803b158015611b2157600080fd5b505afa158015611b35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b599190615165565b611b61612c74565b1415611b71576000925050610636565b6003925050610636565b60029150610636565b60988381548110611b9157fe5b906000526020600020906008020160050154611bab612c74565b1015611bba5760019150610636565b60988381548110611bc757fe5b90600052602060002090600802016006015460001415611bea5760049150610636565b60988381548110611bf757fe5b906000526020600020906008020160060154611c11612c74565b1015611c205760059150610636565b60069150610636565b609a60205281600052604060002081815481106107d157fe5b611c4d816000610794565b50565b600080611c5b612c74565b6001600160a01b038416600090815260a56020526040902060010154909150811115611c8b5760009150506104f4565b50506001600160a01b038116600090815260a560205260409020546104f4565b6000828152606560205260408120611cc9908363ffffffff6139d616565b90505b92915050565b6000828152606560205260408120611cc9908363ffffffff6139e216565b6001600160a01b0391909116600090815260a46020908152604080832093835260019093019052205490565b60985481908110611d3f5760405162461bcd60e51b815260040161052490615cc0565b60988281548110611d4c57fe5b60009182526020909120600890910201546001600160a01b03163314611d845760405162461bcd60e51b815260040161052490615354565b6000611d8f836119ca565b6006811115611d9a57fe5b14611db75760405162461bcd60e51b815260040161052490615b29565b611dbf612c74565b60988381548110611dcc57fe5b906000526020600020906008020160060181905550611e3360988381548110611df157fe5b6000918252602090912060089091020154609880546001600160a01b039092169185908110611e1c57fe5b9060005260206000209060080201600201546139f7565b507fc42cff898171c085fa87ecad4869a5fb22753dddf61048199b8c740c2109fb1182604051611e639190615324565b60405180910390a15050565b60408051808201825260058152644e6f64657360d81b602080830191909152609754925160009333926001600160a01b039091169163ec56a37391611eb691869101615234565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b8152600401611ee89190615324565b60206040518083038186803b158015611f0057600080fd5b505afa158015611f14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f389190615062565b6001600160a01b03161480611f505750611f5061264c565b611f6c5760405162461bcd60e51b815260040161052490615d40565b6000848152609c602052604090206119c0908463ffffffff613ac316565b600081565b6097546001600160a01b031681565b60985481908110611fc15760405162461bcd60e51b815260040161052490615cc0565b609754604051633581777360e01b81526000916001600160a01b031690633581777390611ff090600401615dae565b60206040518083038186803b15801561200857600080fd5b505afa15801561201c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120409190615062565b9050806001600160a01b031663bed5012e336098868154811061205f57fe5b9060005260206000209060080201600101546040518363ffffffff1660e01b815260040161208e929190615264565b60206040518083038186803b1580156120a657600080fd5b505afa1580156120ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120de91906150dd565b6120fa5760405162461bcd60e51b81526004016105249061583c565b61214c6098848154811061210a57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918690811061213557fe5b90600052602060002090600802016001015461308e565b506000612158846119ca565b9050600081600681111561216857fe5b1461223357600181600681111561217b57fe5b14806121925750600481600681111561219057fe5b145b806121a8575060058160068111156121a657fe5b145b806121be575060068160068111156121bc57fe5b145b156121db5760405162461bcd60e51b8152600401610524906154d5565b60028160068111156121e957fe5b14156122075760405162461bcd60e51b815260040161052490615c6f565b600381600681111561221557fe5b14156122335760405162461bcd60e51b8152600401610524906156f1565b600081600681111561224157fe5b1461225e5760405162461bcd60e51b815260040161052490615b86565b609754604051633581777360e01b81526000916001600160a01b03169063358177739061228d90600401615684565b60206040518083038186803b1580156122a557600080fd5b505afa1580156122b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122dd9190615062565b90506060612310609887815481106122f157fe5b60009182526020909120600890910201546001600160a01b031661265e565b905061231b86613be3565b816001600160a01b03166394df393f6098888154811061233757fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b03168860988a8154811061236a57fe5b90600052602060002090600802016002015460988b8154811061238957fe5b9060005260206000209060080201600501546040518563ffffffff1660e01b81526004016123ba949392919061529e565b600060405180830381600087803b1580156123d457600080fd5b505af11580156123e8573d6000803e3d6000fd5b505050506123f5816127b2565b7fdb0c41de0e1a6e61f3ea29d9618edd8bfe8cb4e041a267c54eec70418341272d866040516124249190615324565b60405180910390a1505050505050565b6098818154811061244157fe5b60009182526020918290206008909102018054600180830154600280850154600386015460048701546005880154600689015460078a01805460408051601f6000199c841615610100029c909c0190921698909804998a018d90048d0281018d019097528887526001600160a01b039099169b50959993989297919690959492938301828280156125135780601f106124e857610100808354040283529160200191612513565b820191906000526020600020905b8154815290600101906020018083116124f657829003601f168201915b5050505050905088565b600054610100900460ff16806125365750612536614095565b80612544575060005460ff16155b6125605760405162461bcd60e51b815260040161052490615a75565b600054610100900460ff1615801561258b576000805460ff1961ff0019909116610100171660011790555b6125948261409b565b80156107a6576000805461ff00191690555050565b60008181526065602052604081206104f190614125565b6000828152606560205260409020600201546125de906103ff6138d7565b6118835760405162461bcd60e51b81526004016105249061576a565b6001600160a01b03166000908152609a602052604090205490565b6000611cc98383612624612c74565b614130565b60006104f161263783611c50565b61264084613479565b9063ffffffff61416b16565b60006126588133611cd2565b90505b90565b60606104f18260006129b4565b600082600301546000141561268257506000611ccc565b8183600301541161279b5760038301545b8281116127835760008181526001808601602090815260408084205491889052832054612700926126f4919060028a019086906126d790899063ffffffff61419016565b81526020019081526020016000205461416b90919063ffffffff16565b9063ffffffff6141d216565b6000838152600287016020526040902054909150811461272e57600082815260028601602052604090208190555b60008281526020869052604090205415612752576000828152602086905260408120555b60008281526001860160205260409020541561277a5760008281526001860160205260408120555b50600101612693565b5061279582600163ffffffff61416b16565b60038401555b506000908152600291909101602052604090205490565b609754604051633581777360e01b81526000916001600160a01b0316906335817773906127e19060040161546c565b60206040518083038186803b1580156127f957600080fd5b505afa15801561280d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128319190615062565b9050600080805b845181101561294657826001600160a01b031685828151811061285757fe5b6020026020010151600001516001600160a01b0316146129115781156128d857604051634458328b60e01b81526001600160a01b03851690634458328b906128a59086908690600401615264565b600060405180830381600087803b1580156128bf57600080fd5b505af11580156128d3573d6000803e3d6000fd5b505050505b8481815181106128e457fe5b60200260200101516000015192508481815181106128fe57fe5b602002602001015160200151915061293e565b61293b85828151811061292057fe5b6020026020010151602001518361416b90919063ffffffff16565b91505b600101612838565b5080156129ae57604051634458328b60e01b81526001600160a01b03841690634458328b9061297b9085908590600401615264565b600060405180830381600087803b15801561299557600080fd5b505af11580156129a9573d6000803e3d6000fd5b505050505b50505050565b60606129bf83611816565b15611ccc576001600160a01b038316600090815260a3602052604090205460a25483158015906129fd5750806129fb838663ffffffff61416b16565b105b15612a1557612a12828563ffffffff61416b16565b90505b612a25818363ffffffff61419016565b67ffffffffffffffff81118015612a3b57600080fd5b50604051908082528060200260200182016040528015612a7557816020015b612a62614f97565b815260200190600190039081612a5a5790505b509250815b81831015612c5357600060a28481548110612a9157fe5b9060005260206000209060040201600201549050600060a28581548110612ab457fe5b90600052602060002090600402016003015490506000612ad5898484614130565b9050612ae881600063ffffffff61422516565b15612c45576001600160a01b0389166000908152609f6020526040902060a28054612b6a92919089908110612b1957fe5b6000918252602080832060408051808201825260049094029091018054845260010154838301526001600160a01b038f16845260a0825280842089855290915290912091908563ffffffff61423e16565b612bca60a28781548110612b7a57fe5b6000918252602080832060408051808201825260049094029091018054845260010154838301526001600160a01b038e16845260a18252808420888552909152909120908463ffffffff612e4216565b8887612bdc888763ffffffff61419016565b81518110612be657fe5b60209081029190910101516001600160a01b039091169052612c19612c0c8a8585614130565b829063ffffffff6141d216565b87612c2a888763ffffffff61419016565b81518110612c3457fe5b602002602001015160200181815250505b505050826001019250612a7a565b506001600160a01b038516600090815260a360205260409020555092915050565b609754604051633581777360e01b815260009182916001600160a01b0390911690633581777390612ca79060040161565f565b60206040518083038186803b158015612cbf57600080fd5b505afa158015612cd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf79190615062565b9050806001600160a01b031663ddd1b67e6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d3257600080fd5b505afa158015612d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6a9190615165565b91505090565b612d78614f7d565b6003840154612d8e83600163ffffffff61416b16565b1015612dac5760405162461bcd60e51b815260040161052490615435565b6003840154612dc657612dbf600061424c565b9050612e3b565b6000612dd28584613ac3565b9050612de581600063ffffffff61425f16565b15612dfc57612df4600061424c565b915050612e3b565b8380821015612e085750805b612e10614f7d565b612e29612e23848463ffffffff6141d216565b84614285565b9050612e368782876142d5565b925050505b9392505050565b6003830154612e5882600163ffffffff61416b16565b1015612e765760405162461bcd60e51b815260040161052490615733565b602082015182511115612e9b5760405162461bcd60e51b81526004016105249061548e565b6003830154612ea957612f8d565b6000612eb5848361266b565b9050612ec881600063ffffffff61425f16565b15612ed35750612f8d565b6020808401518451600085815260028801909352604090922054612f0d92612f01919063ffffffff61384a16565b9063ffffffff6142e316565b6000838152600286016020526040812091909155612f3283600163ffffffff61416b16565b90505b84600401548111612f8a576020808501518551600084815260018901909352604090922054612f6e92612f01919063ffffffff61384a16565b6000828152600180880160205260409091209190915501612f35565b50505b505050565b6001830154612fd057600180840182905560028085018390556000838152602086815260408220865181559086015193810193909355910155612f8d565b8083600201541115612ff45760405162461bcd60e51b815260040161052490615a30565b808360020154141561305557600081815260208481526040918290208251808401909352805483526001015490820152613034908363ffffffff61432516565b60008281526020858152604090912082518155910151600190910155612f8d565b60008181526020848152604080832085518155918501516001830155600291820183905581860180548452922001829055819055505050565b609754604051633581777360e01b815260009182916001600160a01b03909116906335817773906130c19060040161557a565b60206040518083038186803b1580156130d957600080fd5b505afa1580156130ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131119190615062565b6001600160a01b038516600090815260a6602090815260408083208784526001019091529020549091501515806131fe57506001600160a01b038416600090815260a6602090815260408083208684526001019091529020541580156131fe5750806001600160a01b031663049e41776040518163ffffffff1660e01b815260040160206040518083038186803b1580156131ab57600080fd5b505afa1580156131bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e39190615165565b6001600160a01b038516600090815260a66020526040902054105b6119c35760405162461bcd60e51b815260040161052490615d77565b6098805460408051610100810182526001600160a01b03898116825260208083018a8152938301898152606084018981524260808601908152600060a0870181815260c0880182815260e089018d815260018c018d559b90925287517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81460088c0290810180546001600160a01b0319169290991691909117885598517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d8158a015593517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81689015591517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d817880155517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81887015590517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d819860155517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81a850155945180519495929491936133d1937f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81b90910192910190614fae565b5050506000858152609960209081526040808320805460018181018355918552838520018590556001600160a01b038a168452609a83529083208054918201815583529120018190556098805461346f91908390811061342d57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918490811061345857fe5b906000526020600020906008020160020154614363565b5095945050505050565b600080613484612c74565b905061348f83611c42565b6001600160a01b0383166000908152609f60205260409020612e3b908263ffffffff613ac316565b6001600160a01b038216600090815260a660209081526040808320848452600190810190925290912054141561352b576001600160a01b038216600090815260a6602052604090205461351190600163ffffffff61419016565b6001600160a01b038316600090815260a660205260409020555b6001600160a01b038216600090815260a6602090815260408083208484526001908101909252909120546135649163ffffffff61419016565b6001600160a01b03909216600090815260a660209081526040808320938352600190930190522055565b600080613599612c74565b90506000609884815481106135aa57fe5b906000526020600020906008020160050154905080821015613600576135f7609885815481106135d657fe5b9060005260206000209060080201600301548261416b90919063ffffffff16565b925050506104f4565b60006136376098868154811061361257fe5b906000526020600020906008020160030154612f01848661419090919063ffffffff16565b905061368b61367e6098878154811061364c57fe5b90600052602060002090600802016003015461367260018561416b90919063ffffffff16565b9063ffffffff61384a16565b839063ffffffff61416b16565b93505050506104f4565b6000818152609b602052604081205460988054839190859081106136b557fe5b90600052602060002090600802016001015490506000609885815481106136d857fe5b90600052602060002090600802016002015490508260001415613718576000828152609e60205260409020600101549250826137185792506104f4915050565b825b60008111801561374757506098868154811061373257fe5b90600052602060002090600802016006015481105b156137c5576098868154811061375957fe5b90600052602060002090600802016005015481106137a4576000838152609e602090815260408083208484529091529020600181015490546137a19190612f0190859061384a565b91505b6000838152609e60209081526040808320938352929052206002015461371a565b50949350505050565b6000838152609c60205260409020612f8d90838363ffffffff61440716565b6001600160a01b0383166000908152609f60205260409020612f8d90838363ffffffff61440716565b6001600160a01b038416600090815260a06020908152604080832086845290915290206129ae90838363ffffffff61440716565b60008261385957506000611ccc565b8282028284828161386657fe5b0414611cc95760405162461bcd60e51b815260040161052490615920565b6000838152609d60205260409020612f8d90838363ffffffff6144c816565b6001600160a01b038416600090815260a16020908152604080832086845290915290206129ae90838363ffffffff6144c816565b3390565b60008281526065602052604090206138f9908263ffffffff61454616565b156107a6576139066138d7565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0316600090815260a46020526040902054151590565b6000828152606560205260409020613985908263ffffffff61455b16565b156107a6576139926138d7565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b6000611cc98383614570565b6000611cc9836001600160a01b0384166145b5565b600080613a02612c74565b6001600160a01b038516600090815260a560205260409020600101549091508114613a3f5760405162461bcd60e51b8152600401610524906157f1565b6001600160a01b038416600090815260a56020526040902054831115613a775760405162461bcd60e51b815260040161052490615895565b6001600160a01b038416600090815260a56020526040902054613aa0908463ffffffff61419016565b6001600160a01b03909416600090815260a5602052604090209390935592915050565b6003820154600090613adc83600163ffffffff61416b16565b1015613afa5760405162461bcd60e51b8152600401610524906156af565b6003830154613b0b57506000611ccc565b81836003015411613bda5760038301545b828111613bc2576000818152600185016020908152604080832054918790528220546002870154613b5892916126f4919063ffffffff61416b16565b905080856002015414613b6d57600285018190555b60008281526020869052604090205415613b91576000828152602086905260408120555b600082815260018601602052604090205415613bb95760008281526001860160205260408120555b50600101613b1c565b50613bd482600163ffffffff61416b16565b60038401555b50506002015490565b609754604051633581777360e01b81526000916001600160a01b031690633581777390613c12906004016159f9565b60206040518083038186803b158015613c2a57600080fd5b505afa158015613c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c629190615062565b90506000613c6e612c74565b9050613c8181600163ffffffff61416b16565b60988481548110613c8e57fe5b9060005260206000209060080201600501819055506000609e600060988681548110613cb657fe5b9060005260206000209060080201600101548152602001908152602001600020600201541115613d2757609e600060988581548110613cf157fe5b60009182526020808320600160089093020191909101548352828101939093526040918201812060020154868252609b90935220555b613d8160988481548110613d3757fe5b90600052602060002090600802016001015460988581548110613d5657fe5b906000526020600020906008020160020154613d7c60018561416b90919063ffffffff16565b6145cd565b613de760988481548110613d9157fe5b6000918252602090912060089091020154609880546001600160a01b039092169186908110613dbc57fe5b906000526020600020906008020160020154613de260018561416b90919063ffffffff16565b6145ec565b613e6c60988481548110613df757fe5b6000918252602090912060089091020154609880546001600160a01b039092169186908110613e2257fe5b90600052602060002090600802016001015460988681548110613e4157fe5b906000526020600020906008020160020154613e6760018661416b90919063ffffffff16565b614615565b613ed260988481548110613e7c57fe5b6000918252602090912060089091020154609880546001600160a01b039092169186908110613ea757fe5b906000526020600020906008020160010154613ecd60018561416b90919063ffffffff16565b614649565b6000613f9e836001600160a01b031663f5b98f4160988781548110613ef357fe5b9060005260206000209060080201600301546040518263ffffffff1660e01b8152600401613f219190615324565b60206040518083038186803b158015613f3957600080fd5b505afa158015613f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f719190615165565b60988681548110613f7e57fe5b90600052602060002090600802016002015461384a90919063ffffffff16565b9050613fdc60988581548110613fb057fe5b90600052602060002090600802016001015482613fd760018661416b90919063ffffffff16565b6146e7565b61404360988581548110613fec57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918790811061401757fe5b9060005260206000209060080201600101548361403e60018761416b90919063ffffffff16565b614706565b6129ae6098858154811061405357fe5b6000918252602090912060089091020154609880546001600160a01b03909216918790811061407e57fe5b90600052602060002090600802016001015461473a565b303b1590565b600054610100900460ff16806140b457506140b4614095565b806140c2575060005460ff16155b6140de5760405162461bcd60e51b815260040161052490615a75565b600054610100900460ff16158015614109576000805460ff1961ff0019909116610100171660011790555b6141116147e2565b61411c60003361180c565b61259482614874565b60006104f1826148ea565b6001600160a01b038316600090815260a0602090815260408083208584529091528120614163908363ffffffff613ac316565b949350505050565b600082820183811015611cc95760405162461bcd60e51b8152600401610524906155f8565b6000611cc983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506148ee565b60008183106141e45750808203611ccc565b7f5b70a077a991facb623c7b2ee44cc539dc6ba345b6636552b8ea97fbbd4d54198383604051614215929190615e94565b60405180910390a1506000611ccc565b6000620f424019821061423457fe5b50620f4240011090565b6129ae84848484600161491a565b614254614f7d565b6104f1826001614285565b6000818311156142775750620f424081830310611ccc565b50620f424082820310611ccc565b61428d614f7d565b600082116142ad5760405162461bcd60e51b815260040161052490615998565b6142b5614f7d565b6040518060400160405280858152602001848152509050611cc981614b01565b612f8d83848484600061491a565b6000611cc983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614b4d565b61432d614f7d565b81518351611cc991614345919063ffffffff61384a16565b6020808501519086015161435e9163ffffffff61384a16565b614285565b60008061436e612c74565b6001600160a01b038516600090815260a560205260409020600101549091508111156143ba576001600160a01b038416600090815260a5602052604090208381556001018190556119c3565b6001600160a01b038416600090815260a5602052604090206001015481146143de57fe5b6001600160a01b038416600090815260a56020526040902054613aa0908463ffffffff61416b16565b61441881600163ffffffff61416b16565b8360030154111561443b5760405162461bcd60e51b8152600401610524906159c2565b60038301546144535760038301819055600483018190555b826004015481111561446757600483018190555b826003015481106144a9576000818152600184016020526040902054614493908363ffffffff61416b16565b6000828152600185016020526040902055612f8d565b60028301546144be908363ffffffff6141d216565b6002840155505050565b80836003015411156144ec5760405162461bcd60e51b8152600401610524906159c2565b60038301546144fd57600383018190555b600081815260018401602052604090205461451e908363ffffffff61416b16565b600082815260018501602052604090205560048301548114612f8d5760048301819055505050565b6000611cc9836001600160a01b038416614b84565b6000611cc9836001600160a01b038416614bce565b815460009082106145935760405162461bcd60e51b8152600401610524906153a4565b8260000182815481106145a257fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b6000838152609c60205260409020612f8d90838363ffffffff614c9416565b6001600160a01b0383166000908152609f60205260409020612f8d90838363ffffffff614c9416565b6001600160a01b038416600090815260a06020908152604080832086845290915290206129ae90838363ffffffff614c9416565b6001600160a01b038316600090815260a46020526040902054614691576001600160a01b038316600090815260a46020908152604080832084905560a25460a3909252909120555b6001600160a01b038316600090815260a460209081526040808320858452600101909152902054612f8d576001600160a01b0392909216600090815260a460209081526040808320938352600190930190522055565b6000838152609d60205260409020612f8d90838363ffffffff614d3716565b6001600160a01b038416600090815260a16020908152604080832086845290915290206129ae90838363ffffffff614d3716565b6001600160a01b038216600090815260a6602090815260408083208484526001019091529020546147a9576001600160a01b038216600090815260a6602052604090205461478f90600163ffffffff61416b16565b6001600160a01b038316600090815260a660205260409020555b6001600160a01b038216600090815260a6602090815260408083208484526001908101909252909120546135649163ffffffff61416b16565b600054610100900460ff16806147fb57506147fb614095565b80614809575060005460ff16155b6148255760405162461bcd60e51b815260040161052490615a75565b600054610100900460ff16158015614850576000805460ff1961ff0019909116610100171660011790555b614858614db1565b614860614db1565b8015611c4d576000805461ff001916905550565b6001600160a01b03811661489a5760405162461bcd60e51b815260040161052490615ae7565b6148ac816001600160a01b0316614e32565b6148c85760405162461bcd60e51b815260040161052490615961565b609780546001600160a01b0319166001600160a01b0392909216919091179055565b5490565b600081848411156149125760405162461bcd60e51b81526004016105249190615341565b505050900390565b600385015461493083600163ffffffff61416b16565b101561494e5760405162461bcd60e51b815260040161052490615435565b801561498857600384015461496a83600163ffffffff61416b16565b10156149885760405162461bcd60e51b815260040161052490615435565b6020830151835111156149ad5760405162461bcd60e51b81526004016105249061548e565b60038501546149bb57612f8a565b60006149c78684613ac3565b90506149da81600063ffffffff61425f16565b156149e55750612f8a565b6000614a0a8560200151612f0187600001518a6002015461384a90919063ffffffff16565b90508215614a3357614a3386614a2d838a600201546141d290919063ffffffff16565b86614407565b600287018190556000614a4d85600163ffffffff61416b16565b90505b876004015481116129a9576020808701518751600084815260018c019093526040832054614a899291612f01919063ffffffff61384a16565b90508415614ae557600082815260018a016020526040902054614ad390614ab6908363ffffffff6141d216565b600084815260018b0160205260409020549063ffffffff6141d216565b600083815260018a0160205260409020555b60008281526001808b0160205260409091209190915501614a50565b6000614b1582600001518360200151614e6b565b8251909150614b2a908263ffffffff6142e316565b82526020820151614b41908263ffffffff6142e316565b60209092019190915250565b60008183614b6e5760405162461bcd60e51b81526004016105249190615341565b506000838581614b7a57fe5b0495945050505050565b6000614b9083836145b5565b614bc657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ccc565b506000611ccc565b60008181526001830160205260408120548015614c8a5783546000198083019190810190600090879083908110614c0157fe5b9060005260206000200154905080876000018481548110614c1e57fe5b600091825260208083209091019290925582815260018981019092526040902090840190558654879080614c4e57fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611ccc565b6000915050611ccc565b8083600301541115614cb85760405162461bcd60e51b81526004016105249061562f565b6003830154614cd05760038301819055600483018190555b8260040154811115614ce457600483018190555b82600301548110614d2257600081815260208490526040902054614d0e908363ffffffff61416b16565b600082815260208590526040902055612f8d565b60028301546144be908363ffffffff61416b16565b8083600301541115614d5b5760405162461bcd60e51b81526004016105249061562f565b6003830154614d6c57600383018190555b600081815260208490526040902054614d8b908363ffffffff61416b16565b60008281526020859052604090205560048301548114612f8d5760048301819055505050565b600054610100900460ff1680614dca5750614dca614095565b80614dd8575060005460ff16155b614df45760405162461bcd60e51b815260040161052490615a75565b600054610100900460ff16158015614860576000805460ff1961ff0019909116610100171660011790558015611c4d576000805461ff001916905550565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590614163575050151592915050565b6000828281811115614e8757614e818282614ebb565b90925090505b8015614eb357614e9d828263ffffffff614ebe16565b9150614ea98282614ebb565b9092509050614e87565b509392505050565b91565b6000611cc983836040518060400160405280601881526020017f536166654d6174683a206d6f64756c6f206279207a65726f000000000000000081525060008183614f1c5760405162461bcd60e51b81526004016105249190615341565b50828481614f2657fe5b06949350505050565b60405180610100016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081525090565b604051806040016040528060008152602001600081525090565b604080518082019091526000808252602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614fef57805160ff191683800117855561501c565b8280016001018555821561501c579182015b8281111561501c578251825591602001919060010190615001565b5061502892915061502c565b5090565b61265b91905b808211156150285760008155600101615032565b600060208284031215615057578081fd5b8135611cc981615ece565b600060208284031215615073578081fd5b8151611cc981615ece565b60008060408385031215615090578081fd5b823561509b81615ece565b946020939093013593505050565b6000806000606084860312156150bd578081fd5b83356150c881615ece565b95602085013595506040909401359392505050565b6000602082840312156150ee578081fd5b81518015158114611cc9578182fd5b60006020828403121561510e578081fd5b5035919050565b60008060408385031215615127578182fd5b82359150602083013561513981615ece565b809150509250929050565b60008060408385031215615156578182fd5b50508035926020909101359150565b600060208284031215615176578081fd5b5051919050565b600080600080600060808688031215615194578081fd5b853594506020860135935060408601359250606086013567ffffffffffffffff808211156151c0578283fd5b81880189601f8201126151d1578384fd5b80359250818311156151e1578384fd5b8960208483010111156151f2578384fd5b6020810194505050809150509295509295909350565b60008151808452615220816020860160208601615ea2565b601f01601f19169290920160200192915050565b60008251615246818460208701615ea2565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b600061010060018060a01b038b1683528960208401528860408401528760608401528660808401528560a08401528460c08401528060e084015261530a81840185615208565b9b9a5050505050505050505050565b901515815260200190565b90815260200190565b602081016007831061533b57fe5b91905290565b600060208252611cc96020830184615208565b60208082526030908201527f4f6e6c7920746f6b656e20686f6c646572732063616e2063616e63656c20646560408201526f1b1959d85d1a5bdb881c995c5d595cdd60821b606082015260800190565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252602f908201527f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60408201526e0818591b5a5b881d1bc819dc985b9d608a1b606082015260800190565b6020808252601f908201527f43616e6e6f74207265647563652076616c756520696e20746865207061737400604082015260600190565b602080825260089082015267283ab734b9b432b960c11b604082015260600190565b60208082526027908201527f496e6372656173696e67206f662076616c756573206973206e6f7420696d706c604082015266195b595b9d195960ca1b606082015260800190565b60208082526028908201527f5468652064656c65676174696f6e20686173206265656e20616c7265616479206040820152671858d8d95c1d195960c21b606082015260800190565b60208082526038908201527f56616c696461746f72206973206e6f7420617574686f72697a656420746f206160408201527f63636570742064656c65676174696f6e20726571756573740000000000000000606082015260800190565b6020808252600f908201526e21b7b739ba30b73a39a437b63232b960891b604082015260600190565b60208082526035908201527f5468652076616c696461746f72206973206e6f742063757272656e746c7920616040820152746363657074696e67206e657720726571756573747360581b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526016908201527510d85b9b9bdd08185919081d1bc81d1a19481c185cdd60521b604082015260600190565b6020808252600b908201526a54696d6548656c7065727360a81b604082015260600190565b6020808252601190820152702a37b5b2b72630bab731b42637b1b5b2b960791b604082015260600190565b60208082526022908201527f43616e6e6f742063616c63756c6174652076616c756520696e207468652070616040820152611cdd60f21b606082015260800190565b60208082526022908201527f5468652064656c65676174696f6e2072657175657374206973206f7574646174604082015261195960f21b606082015260800190565b6020808252601e908201527f43616e2774207265647563652076616c756520696e2074686520706173740000604082015260600190565b60208082526030908201527f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60408201526f2061646d696e20746f207265766f6b6560801b606082015260800190565b6020808252601b908201527f43616e6e6f74207265717565737420756e64656c65676174696f6e0000000000604082015260600190565b6020808252602b908201527f546865726520617265206e6f2064656c65676174696f6e20726571756573747360408201526a040e8d0d2e640dadedce8d60ab1b606082015260800190565b6020808252818101527f4e6f207065726d697373696f6e7320746f206163636570742072657175657374604082015260600190565b6020808252600a908201526929b5b0b632aa37b5b2b760b11b604082015260600190565b6020808252601b908201527f556e6c6f636b696e6720616d6f756e7420697320746f6f206269670000000000604082015260600190565b60208082526034908201527f546f6b656e20686f6c64657220646f6573206e6f74206861766520656e6f75676040820152736820746f6b656e7320746f2064656c656761746560601b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527f41646472657373206973206e6f7420636f6e7472616374000000000000000000604082015260600190565b60208082526010908201526f4469766973696f6e206279207a65726f60801b604082015260600190565b6020808252601d908201527f43616e6e6f742073756274726163742066726f6d207468652070617374000000604082015260600190565b60208082526017908201527f44656c65676174696f6e506572696f644d616e61676572000000000000000000604082015260600190565b60208082526025908201527f43616e6e6f742070757420736c617368696e67206576656e7420696e20746865604082015264081c185cdd60da1b606082015260800190565b6020808252602e908201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560408201526d195b881a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252600a9082015269546f6b656e537461746560b01b604082015260600190565b60208082526022908201527f436f6e74726163744d616e616765722061646472657373206973206e6f742073604082015261195d60f21b606082015260800190565b6020808252603a908201527f546f6b656e20686f6c6465727320617265206f6e6c792061626c6520746f206360408201527f616e63656c2050524f504f5345442064656c65676174696f6e73000000000000606082015260800190565b60208082526027908201527f43616e6e6f74207365742064656c65676174696f6e20737461746520746f206160408201526618d8d95c1d195960ca1b606082015260800190565b60208082526025908201527f546869732064656c65676174696f6e20706572696f64206973206e6f7420616c6040820152641b1bddd95960da1b606082015260800190565b6020808252603e908201527f416d6f756e7420646f6573206e6f74206d656574207468652076616c6964617460408201527f6f722773206d696e696d756d2064656c65676174696f6e20616d6f756e740000606082015260800190565b60208082526031908201527f5468652064656c65676174696f6e20686173206265656e2063616e63656c6c656040820152703210313c903a37b5b2b7103437b63232b960791b606082015260800190565b60208082526019908201527f44656c65676174696f6e20646f6573206e6f7420657869737400000000000000604082015260600190565b60208082526029908201527f5065726d697373696f6e2064656e69656420746f207265717565737420756e6460408201526832b632b3b0ba34b7b760b91b606082015260800190565b60208082526019908201527f4d6573736167652073656e64657220697320696e76616c696400000000000000604082015260600190565b6020808252601e908201527f4c696d6974206f662076616c696461746f727320697320726561636865640000604082015260600190565b60208082526010908201526f56616c696461746f725365727669636560801b604082015260600190565b6020808252602f908201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560408201526e103937b632b9903337b91039b2b63360891b606082015260800190565b60006020825260018060a01b038351166020830152602083015160408301526040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e08301516101008081850152506119c0610120840182615208565b918252602082015260400190565b60005b83811015615ebd578181015183820152602001615ea5565b838111156129ae5750506000910152565b6001600160a01b0381168114611c4d57600080fdfea264697066735822122088c330383e3eca2d1dd22b553b5b109eafd04aa92a00d266c363bddb03bdaf0064736f6c634300060a0033
Deployed Bytecode Sourcemap
2253:33346:8:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10230:156;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;18180:181;;;;;;;;;:::i;:::-;;;;;;;;6907:465;;;;;;;;;:::i;19200:142::-;;;;;;;;;:::i;:::-;;6580:176;;;;;;;;;:::i;4822:54::-;;;;;;;;;:::i;17134:571::-;;;;;;;;;:::i;8031:1965::-;;;;;;;;;:::i;3900:112:0:-;;;;;;;;;:::i;6762:139:8:-;;;;;;;;;:::i;13944:2609::-;;;;;;;;;:::i;4262:223:0:-;;;;;;;;;:::i;21120:180:8:-;;;;;;;;;:::i;:::-;;;;;;;;5436:205:0;;;;;;;;;:::i;18546:154:8:-;;;;;;;;;:::i;17711:240::-;;;;;;;;;:::i;19581:1206::-;;;;;;;;;:::i;:::-;;;;;;;;4922:54;;;;;;;;;:::i;19348:92::-;;;;;;;;;:::i;20793:321::-;;;;;;;;;:::i;3583:136:0:-;;;;;;;;;:::i;:::-;;;;;;;;2568:137;;;;;;;;;:::i;18367:173:8:-;;;;;;;;;:::i;10768:586::-;;;;;;;;;:::i;18990:204::-;;;;;;;;;:::i;1758:49:0:-;;;:::i;1187:38:31:-;;;:::i;11734:1868:8:-;;;;;;;;;:::i;4747:31::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;18853:131;;;;;;;;;:::i;2873:125:0:-;;;;;;;;;:::i;4719:226::-;;;;;;;;;:::i;18706:141:8:-;;;;;;;;;:::i;17957:217::-;;;;;;;;;:::i;10230:156::-;10323:4;10346:33;10372:6;10346:25;:33::i;:::-;10339:40;;10230:156;;;;:::o;18180:181::-;18289:17;;:::i;:::-;6508:11;:18;18266:12;;6493:33;;6485:71;;;;-1:-1:-1;;;6485:71:8;;;;;;;;;;;;;;;;;18329:11:::1;18341:12;18329:25;;;;;;;;;::::0;;;::::1;::::0;;;;18322:32:::1;::::0;;::::1;::::0;;::::1;::::0;;18329:25:::1;::::0;;;::::1;::::0;;::::1;18322:32:::0;;-1:-1:-1;;;;;18322:32:8::1;::::0;;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;::::1;::::0;::::1;::::0;;;;;::::1;::::0;::::1;::::0;;;;;::::1;::::0;::::1;::::0;;;;;::::1;::::0;::::1;::::0;;;;;::::1;::::0;::::1;::::0;;;;;;::::1;;::::0;;::::1;-1:-1:-1::0;;18322:32:8;;;::::1;;;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;;;;18329:25;;18322:32;;;;;;;;::::1;::::0;;;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;6566:1;18180:181:::0;;;;:::o;6907:465::-;1722:230:31;;;;;;;;;;;-1:-1:-1;;;1722:230:31;;;;;;;;1796:15;;1832:30;;-1:-1:-1;;1868:10:31;;-1:-1:-1;;;;;1796:15:31;;;;:25;;1832:30;;1722:230;;1832:30;;;;;;;;;;;;;;;;1822:41;;;;;;1796:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1796:82:31;;:96;;;;1882:10;:8;:10::i;:::-;1775:159;;;;-1:-1:-1;;;1775:159:31;;;;;;;;;7098:39:8::1;7140:40;7173:6;7140:32;:40::i;:::-;-1:-1:-1::0;;;;;7211:46:8;::::1;;::::0;;;:38:::1;:46;::::0;;;;;;;:59;;;;;;;;7098:82;;-1:-1:-1;7211:107:8::1;::::0;7312:5;7211:107:::1;:100;:107;:::i;:::-;7190:128;;7328:37;7349:15;7328:20;:37::i;:::-;1944:1:31;6907:465:8::0;;;;;;:::o;19200:142::-;19269:66;19290:44;19320:6;19328:5;19290:29;:44::i;:::-;19269:20;:66::i;:::-;19200:142;;:::o;6580:176::-;6661:4;6684:65;6717:11;6730:18;:16;:18::i;4822:54::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;17134:571::-;1722:230:31;;;;;;;;;;;-1:-1:-1;;;1722:230:31;;;;;;;;1796:15;;1832:30;;1722:230;;1868:10;;-1:-1:-1;;;;;1796:15:31;;;;:25;;1832:30;;1722:230;;1832:30;;;;;;;;;;;;;;;;1822:41;;;;;;1796:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1796:82:31;;:96;;;;1882:10;:8;:10::i;:::-;1775:159;;;;-1:-1:-1;;;1775:159:31;;;;;;;;;17222:17:8::1;17242:18;:16;:18::i;:::-;17222:38;;17270:41;;:::i;:::-;17326:34;::::0;;;:21:::1;:34;::::0;;;;:68:::1;::::0;17373:6;17381:12;17326:68:::1;:46;:68;:::i;:::-;17404:43;::::0;;;:30:::1;:43;::::0;;;;17270:124;;-1:-1:-1;17404:85:8::1;::::0;17270:124;17476:12;17404:85:::1;:58;:85;:::i;:::-;17517:32;::::0;;;:19:::1;:32;::::0;;;;17499:78:::1;::::0;17551:11;17564:12;17499:17:::1;:78::i;:::-;17601:96;::::0;;::::1;::::0;::::1;::::0;;;;;::::1;::::0;;::::1;::::0;;;;;;;;;17587:8:::1;:111:::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;17587:111:8;;;;;;;;;::::1;::::0;;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;17134:571:8:o;8031:1965::-;8247:15;;:47;;-1:-1:-1;;;8247:47:8;;8194:33;;-1:-1:-1;;;;;8247:15:8;;:27;;:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8392:15;;:54;;-1:-1:-1;;;8392:54:8;;8194:101;;-1:-1:-1;8305:47:8;;-1:-1:-1;;;;;8392:15:8;;;;:27;;:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8486:15;;:41;;-1:-1:-1;;;8486:41:8;;8305:142;;-1:-1:-1;8457:18:8;;-1:-1:-1;;;;;8486:15:8;;;;:27;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8573:15;;:41;;-1:-1:-1;;;8573:41:8;;8457:71;;-1:-1:-1;8538:21:8;;-1:-1:-1;;;;;8573:15:8;;;;:27;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8647:60;;-1:-1:-1;;;8647:60:8;;8538:77;;-1:-1:-1;;;;;;8647:39:8;;;;;:60;;8687:11;;8700:6;;8647:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8626:160;;;;-1:-1:-1;;;8626:160:8;;;;;;;;;8817:51;;-1:-1:-1;;;8817:51:8;;-1:-1:-1;;;;;8817:38:8;;;;;:51;;8856:11;;8817:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8796:145;;;;-1:-1:-1;;;8796:145:8;;;;;;;;;8972:67;;-1:-1:-1;;;8972:67:8;;-1:-1:-1;;;;;8972:49:8;;;;;:67;;9022:16;;8972:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8951:142;;;;-1:-1:-1;;;8951:142:8;;;;;;;;;9124:52;;-1:-1:-1;;;9124:52:8;;-1:-1:-1;;;;;9124:39:8;;;;;:52;;9164:11;;9124:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9103:143;;;;-1:-1:-1;;;9103:143:8;;;;;;;;;9256:52;9284:10;9296:11;9256:27;:52::i;:::-;;9319:39;9361:44;9394:10;9361:32;:44::i;:::-;9319:86;;9416:17;9436:132;9464:10;9488:11;9513:6;9533:16;9563:4;;9436:132;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;9436:14:8;;-1:-1:-1;;;9436:132:8:i;:::-;9416:152;;9623:18;9644:10;-1:-1:-1;;;;;9644:20:8;;9665:10;9644:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9623:53;;9686:27;9716:10;-1:-1:-1;;;;;9716:51:8;;9768:10;9716:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9686:93;;9814:22;9797:13;:39;;9789:104;;;;-1:-1:-1;;;9789:104:8;;;;;;;;;9909:32;9928:12;9909:32;;;;;;;;;;;;;;;9952:37;9973:15;9952:20;:37::i;:::-;8031:1965;;;;;;;;;;;;;:::o;3900:112:0:-;3957:7;3983:12;;;:6;:12;;;;;:22;;;;3900:112::o;6762:139:8:-;6833:4;6856:38;6887:6;6856:30;:38::i;13944:2609::-;6508:11;:18;14023:12;;6493:33;;6485:71;;;;-1:-1:-1;;;6485:71:8;;;;;;;;;14081:15:::1;14055:22;14064:12;14055:8;:22::i;:::-;:41;;;;;;;;;14047:81;;;;-1:-1:-1::0;;;14047:81:8::1;;;;;;;;;14191:15;::::0;:47:::1;::::0;-1:-1:-1;;;14191:47:8;;14138:33:::1;::::0;-1:-1:-1;;;;;14191:15:8::1;::::0;:27:::1;::::0;:47:::1;::::0;::::1;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14138:101;;14306:10;-1:-1:-1::0;;;;;14270:46:8::1;:11;14282:12;14270:25;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;;:32:::0;-1:-1:-1;;;;;14270:32:8::1;:46;::::0;:215:::1;;-1:-1:-1::0;14333:51:8::1;::::0;-1:-1:-1;;;14333:51:8;;-1:-1:-1;;;;;14333:39:8;::::1;::::0;::::1;::::0;:51:::1;::::0;14373:10:::1;::::0;14333:51:::1;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:151;;;;-1:-1:-1::0;14441:43:8::1;::::0;-1:-1:-1;;;14441:43:8;;-1:-1:-1;;;;;14441:31:8;::::1;::::0;::::1;::::0;:43:::1;::::0;14473:10:::1;::::0;14441:43:::1;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14400:11;14412:12;14400:25;;;;;;;;;;;;;;;;;;:37;;;:84;14333:151;14249:294;;;;-1:-1:-1::0;;;14249:294:8::1;;;;;;;;;14609:15;::::0;:48:::1;::::0;-1:-1:-1;;;14609:48:8;;14553:35:::1;::::0;-1:-1:-1;;;;;14609:15:8::1;::::0;:27:::1;::::0;:48:::1;::::0;::::1;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14755:15;::::0;:54:::1;::::0;-1:-1:-1;;;14755:54:8;;14553:105;;-1:-1:-1;14668:47:8::1;::::0;-1:-1:-1;;;;;14755:15:8;;::::1;::::0;:27:::1;::::0;:54:::1;::::0;::::1;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14668:142;;14820:150;14877:11;14889:12;14877:25;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;;:32:::0;14923:11:::1;:25:::0;;-1:-1:-1;;;;;14877:32:8;;::::1;::::0;14935:12;;14923:25;::::1;;;;;;;;;;;;;;;:37;;;14820:43;:150::i;:::-;14980:29;14998:10;14980:17;:29::i;:::-;15056:42;15085:12;15056:28;:42::i;:::-;15019:11;15031:12;15019:25;;;;;;;;;;;;;;;;;;:34;;:79;;;;15108:24;15135:53;15175:12;15135:39;:53::i;:::-;15108:80;;15198:164;15243:11;15255:12;15243:25;;;;;;;;;;;;;;;;;;:37;;;15294:19;15327:11;15339:12;15327:25;;;;;;;;;;;;;;;;;;:34;;;15198:31;:164::i;:::-;15372:156;15414:11;15426:12;15414:25;;;;;;;;;;;;;;;;;;:32;;;;;;;;;;-1:-1:-1::0;;;;;15414:32:8::1;15460:19;15493:11;15505:12;15493:25;;;;;;;;;;;;;;;;;;:34;;;15372:28;:156::i;:::-;15538:218;15591:11;15603:12;15591:25;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;;:32:::0;15637:11:::1;:25:::0;;-1:-1:-1;;;;;15591:32:8;;::::1;::::0;15649:12;;15637:25;::::1;;;;;;;;;;;;;;;:37;;;15688:19;15721:11;15733:12;15721:25;;;;;;;;;;;;;;;;;;:34;;;15538:39;:218::i;:::-;15766:20;15789:122;15813:23;-1:-1:-1::0;;;;;15813:40:8::1;;15867:11;15879:12;15867:25;;;;;;;;;;;;;;;;;;:42;;;15813:97;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15789:19:::0;;:122:::1;:23;:122;:::i;:::-;15766:145;;15921:169;15975:11;15987:12;15975:25;;;;;;;;;;;;;;;;;;:37;;;16026:15;16055:11;16067:12;16055:25;;;;;;;;;;;;;;;;;;:34;;;15921:40;:169::i;:::-;16100:223;16162:11;16174:12;16162:25;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;;:32:::0;16208:11:::1;:25:::0;;-1:-1:-1;;;;;16162:32:8;;::::1;::::0;16220:12;;16208:25;::::1;;;;;;;;;;;;;;;:37;;;16259:15;16288:11;16300:12;16288:25;;;;;;;;;;;;;;;;;;:34;;;16100:48;:223::i;:::-;16333:17;-1:-1:-1::0;;;;;16333:42:8::1;;16389:11;16401:12;16389:25;;;;;;;;;;;;;;;;;;:32;;;;;;;;;;-1:-1:-1::0;;;;;16389:32:8::1;16435:12;16461:11;16473:12;16461:25;;;;;;;;;;;;;;;;;;:34;;;16333:163;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;16511:35;16533:12;16511:35;;;;;;;;;;;;;;;6566:1;;;;;13944:2609:::0;;:::o;4262:223:0:-;4353:12;;;;:6;:12;;;;;:22;;;4345:45;;4377:12;:10;:12::i;4345:45::-;4337:105;;;;-1:-1:-1;;;4337:105:0;;;;;;;;;4453:25;4464:4;4470:7;4453:10;:25::i;21120:180:8:-;21188:4;21211:22;21226:6;21211:14;:22::i;:::-;:82;;;;-1:-1:-1;;21278:8:8;:15;-1:-1:-1;;;;;21237:38:8;;;;;;;;:30;:38;;;;;;:56;;21120:180::o;5436:205:0:-;5533:12;:10;:12::i;:::-;-1:-1:-1;;;;;5522:23:0;:7;-1:-1:-1;;;;;5522:23:0;;5514:83;;;;-1:-1:-1;;;5514:83:0;;;;;;;;;5608:26;5620:4;5626:7;5608:11;:26::i;18546:154:8:-;18628:4;18651:35;;;:22;:35;;;;;:42;;18546:154::o;17711:240::-;1722:230:31;;;;;;;;;;;-1:-1:-1;;;1722:230:31;;;;;;;;1796:15;;1832:30;;-1:-1:-1;;1868:10:31;;-1:-1:-1;;;;;1796:15:31;;;;:25;;1832:30;;1722:230;;1832:30;;;;;;;;;;;;;;;;1822:41;;;;;;1796:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1796:82:31;;:96;;;;1882:10;:8;:10::i;:::-;1775:159;;;;-1:-1:-1;;;1775:159:31;;;;;;;;;17866:43:8::1;::::0;;;:30:::1;:43;::::0;;;;:78:::1;::::0;17938:5;17866:78:::1;:71;:78;:::i;:::-;17859:85;;1944:1:31;17711:240:8::0;;;;;:::o;19581:1206::-;6508:11;:18;19675:11;;19652:12;;6493:33;;6485:71;;;;-1:-1:-1;;;6485:71:8;;;;;;;;;19702:11:::1;19714:12;19702:25;;;;;;;;;;;;;;;;;;:33;;;19739:1;19702:38;19698:1083;;;19760:11;19772:12;19760:25;;;;;;;;;;;;;;;;;;:34;;;19798:1;19760:39;19756:457;;;19857:15;::::0;:42:::1;::::0;-1:-1:-1;;;19857:42:8;;19819:23:::1;::::0;-1:-1:-1;;;;;19857:15:8::1;::::0;:27:::1;::::0;:42:::1;::::0;::::1;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19819:81;;19944:11;-1:-1:-1::0;;;;;19944:28:8::1;;19973:11;19985:12;19973:25;;;;;;;;;;;;;;;;;;:33;;;19944:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19922:18;:16;:18::i;:::-;:85;19918:221;;;20038:14;20031:21;;;;;19918:221;20106:14;20099:21;;;;;19756:457;20184:14;20177:21;;;;19698:1083;20268:11;20280:12;20268:25;;;;;;;;;;;;;;;;;;:33;;;20247:18;:16;:18::i;:::-;:54;20243:528;;;20328:14;20321:21;;;;20243:528;20385:11;20397:12;20385:25;;;;;;;;;;;;;;;;;;:34;;;20423:1;20385:39;20381:376;;;20455:15;20448:22;;;;20381:376;20542:11;20554:12;20542:25;;;;;;;;;;;;;;;;;;:34;;;20521:18;:16;:18::i;:::-;:55;20517:222;;;20611:28;20604:35;;;;20517:222;20701:15;20694:22;;;;4922:54:::0;;;;;;;;;;;;;;;;;;19348:92;19408:25;19423:6;19431:1;19408:14;:25::i;:::-;19348:92;:::o;20793:321::-;20869:4;20885:17;20905:18;:16;:18::i;:::-;-1:-1:-1;;;;;20937:35:8;;;;;;:27;:35;;;;;:41;;;20885:38;;-1:-1:-1;20937:56:8;-1:-1:-1;20933:175:8;;;21016:1;21009:8;;;;;20933:175;-1:-1:-1;;;;;;;21055:35:8;;;;;;:27;:35;;;;;:42;21048:49;;3583:136:0;3656:7;3682:12;;;:6;:12;;;;;:30;;3706:5;3682:30;:23;:30;:::i;:::-;3675:37;;3583:136;;;;;:::o;2568:137::-;2637:4;2660:12;;;:6;:12;;;;;:38;;2690:7;2660:38;:29;:38;:::i;18367:173:8:-;-1:-1:-1;;;;;18479:29:8;;;;18456:4;18479:29;;;:21;:29;;;;;;;;:54;;;:41;;;;:54;;;;;18367:173::o;10768:586::-;6508:11;:18;10851:12;;6493:33;;6485:71;;;;-1:-1:-1;;;6485:71:8;;;;;;;;;10897:11:::1;10909:12;10897:25;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;;:32:::0;-1:-1:-1;;;;;10897:32:8::1;10883:10;:46;10875:107;;;;-1:-1:-1::0;;;10875:107:8::1;;;;;;;;;11026:14;11000:22;11009:12;11000:8;:22::i;:::-;:40;;;;;;;;;10992:111;;;;-1:-1:-1::0;;;10992:111:8::1;;;;;;;;;11151:18;:16;:18::i;:::-;11114:11;11126:12;11114:25;;;;;;;;;;;;;;;;;;:34;;:55;;;;11179:107;11219:11;11231:12;11219:25;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;;:32:::0;11253:11:::1;:25:::0;;-1:-1:-1;;;;;11219:32:8;;::::1;::::0;11265:12;;11253:25;::::1;;;;;;;;;;;;;;;:32;;;11179:39;:107::i;:::-;;11302:45;11334:12;11302:45;;;;;;;;;;;;;;;10768:586:::0;;:::o;18990:204::-;1722:230:31;;;;;;;;;;;-1:-1:-1;;;1722:230:31;;;;;;;;1796:15;;1832:30;;-1:-1:-1;;1868:10:31;;-1:-1:-1;;;;;1796:15:31;;;;:25;;1832:30;;1722:230;;1832:30;;;;;;;;;;;;;;;;1822:41;;;;;;1796:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1796:82:31;;:96;;;;1882:10;:8;:10::i;:::-;1775:159;;;;-1:-1:-1;;;1775:159:31;;;;;;;;;19128:34:8::1;::::0;;;:21:::1;:34;::::0;;;;:59:::1;::::0;19181:5;19128:59:::1;:52;:59;:::i;1758:49:0:-:0;1803:4;1758:49;:::o;1187:38:31:-;;;-1:-1:-1;;;;;1187:38:31;;:::o;11734:1868:8:-;6508:11;:18;11817:12;;6493:33;;6485:71;;;;-1:-1:-1;;;6485:71:8;;;;;;;;;11894:15:::1;::::0;:47:::1;::::0;-1:-1:-1;;;11894:47:8;;11841:33:::1;::::0;-1:-1:-1;;;;;11894:15:8::1;::::0;:27:::1;::::0;:47:::1;::::0;::::1;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11841:101;;11973:16;-1:-1:-1::0;;;;;11973:42:8::1;;12016:10;12028:11;12040:12;12028:25;;;;;;;;;;;;;;;;;;:37;;;11973:93;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11952:163;;;;-1:-1:-1::0;;;11952:163:8::1;;;;;;;;;12125:100;12153:11;12165:12;12153:25;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;;:32:::0;12187:11:::1;:25:::0;;-1:-1:-1;;;;;12153:32:8;;::::1;::::0;12199:12;;12187:25;::::1;;;;;;;;;;;;;;;:37;;;12125:27;:100::i;:::-;;12244:18;12265:22;12274:12;12265:8;:22::i;:::-;12244:43:::0;-1:-1:-1;12317:14:8::1;12301:12;:30;;;;;;;;;12297:610;;12367:14;12351:12;:30;;;;;;;;;:81;;;-1:-1:-1::0;12417:15:8::1;12401:12;:31;;;;;;;;;12351:81;:145;;;-1:-1:-1::0;12468:28:8::1;12452:12;:44;;;;;;;;;12351:145;:196;;;-1:-1:-1::0;12532:15:8::1;12516:12;:31;;;;;;;;;12351:196;12347:550;;;12579:50;;-1:-1:-1::0;;;12579:50:8::1;;;;;;;;12347:550;12670:14;12654:12;:30;;;;;;;;;12650:247;;;12704:59;;-1:-1:-1::0;;;12704:59:8::1;;;;;;;;12650:247;12804:14;12788:12;:30;;;;;;;;;12784:113;;;12838:44;;-1:-1:-1::0;;;12838:44:8::1;;;;;;;;12784:113;12940:14;12924:12;:30;;;;;;;;;12916:82;;;;-1:-1:-1::0;;;12916:82:8::1;;;;;;;;;13073:15;::::0;:48:::1;::::0;-1:-1:-1;;;13073:48:8;;13017:35:::1;::::0;-1:-1:-1;;;;;13073:15:8::1;::::0;:27:::1;::::0;:48:::1;::::0;::::1;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13017:105;;13133:39;13175:66;13208:11;13220:12;13208:25;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;;:32:::0;-1:-1:-1;;;;;13208:32:8::1;13175;:66::i;:::-;13133:108;;13252:33;13272:12;13252:19;:33::i;:::-;13296:17;-1:-1:-1::0;;;;;13296:37:8::1;;13347:11;13359:12;13347:25;;;;;;;;;;;;;;;;;;:32;;;;;;;;;;-1:-1:-1::0;;;;;13347:32:8::1;13393:12;13419:11;13431:12;13419:25;;;;;;;;;;;;;;;;;;:32;;;13465:11;13477:12;13465:25;;;;;;;;;;;;;;;;;;:33;;;13296:203;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;13510:37;13531:15;13510:20;:37::i;:::-;13563:32;13582:12;13563:32;;;;;;;;;;;;;;;6566:1;;;;11734:1868:::0;;:::o;4747:31::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4747:31:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4747:31:8;;;;-1:-1:-1;4747:31:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;18853:131::-;1024:12:23;;;;;;;;:31;;;1040:15;:13;:15::i;:::-;1024:47;;;-1:-1:-1;1060:11:23;;;;1059:12;1024:47;1016:106;;;;-1:-1:-1;;;1016:106:23;;;;;;;;;1129:19;1152:12;;;;;;1151:13;1170:80;;;;1198:12;:19;;-1:-1:-1;;;;1198:19:23;;;;;1225:18;1213:4;1225:18;;;1170:80;18937:40:8::1;18960:16;18937:22;:40::i;:::-;1268:14:23::0;1264:55;;;1307:5;1292:20;;-1:-1:-1;;1292:20:23;;;18853:131:8;;:::o;2873:125:0:-;2936:7;2962:12;;;:6;:12;;;;;:29;;:27;:29::i;4719:226::-;4811:12;;;;:6;:12;;;;;:22;;;4803:45;;4835:12;:10;:12::i;4803:45::-;4795:106;;;;-1:-1:-1;;;4795:106:0;;;;;;;;18706:141:8;-1:-1:-1;;;;;18806:27:8;18783:4;18806:27;;;:19;:27;;;;;:34;;18706:141::o;17957:217::-;18062:4;18085:82;18127:6;18135:11;18148:18;:16;:18::i;:::-;18085:41;:82::i;27124:179::-;27192:4;27215:81;27258:37;27288:6;27258:29;:37::i;:::-;27215:38;27246:6;27215:30;:38::i;:::-;:42;:81;:42;:81;:::i;3104:112:31:-;3147:4;3170:39;3147:4;3198:10;3170:7;:39::i;:::-;3163:46;;3104:112;;:::o;31883:192:8:-;31966:39;32028:40;32058:6;32066:1;32028:29;:40::i;3265:925:30:-;3359:4;3379:8;:30;;;3413:1;3379:35;3375:74;;;-1:-1:-1;3437:1:30;3430:8;;3375:74;3497:5;3463:8;:30;;;:39;3459:686;;3532:30;;;;3518:558;3569:5;3564:1;:10;3518:558;;3599:14;3677:24;;;:21;;;;:24;;;;;;;;;3645:19;;;;;;;3616:86;;:49;;3645:19;3616:14;;;;3599;;3631:8;;3699:1;;3631:8;:5;:8;:::i;:::-;3616:24;;;;;;;;;;;;:28;;:49;;;;:::i;:::-;:60;:86;:60;:86;:::i;:::-;3724:17;;;;:14;;;:17;;;;;;3599:103;;-1:-1:-1;3724:30:30;;3720:106;;3778:17;;;;:14;;;:17;;;;;:29;;;3720:106;3869:1;3847:19;;;;;;;;;;;:23;3843:96;;3901:16;:19;;;;;;;;;;3894:26;3843:96;3987:1;3960:24;;;:21;;;:24;;;;;;:28;3956:106;;4019:24;;;;:21;;;:24;;;;;4012:31;3956:106;-1:-1:-1;3576:3:30;;3518:558;;;-1:-1:-1;4122:12:30;:5;4132:1;4122:12;:9;:12;:::i;:::-;4089:30;;;:45;3459:686;-1:-1:-1;4162:21:30;;;;:14;;;;;:21;;;;;;;3265:925::o;32081:889:8:-;32199:15;;:39;;-1:-1:-1;;;32199:39:8;;32170:17;;-1:-1:-1;;;;;32199:15:8;;:27;;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;32170:69;-1:-1:-1;32249:22:8;;;32331:515;32352:15;:22;32348:1;:26;32331:515;;;32428:14;-1:-1:-1;;;;;32399:43:8;:15;32415:1;32399:18;;;;;;;;;;;;;;:25;;;-1:-1:-1;;;;;32399:43:8;;32395:441;;32466:22;;32462:125;;32512:56;;-1:-1:-1;;;32512:56:8;;-1:-1:-1;;;;;32512:20:8;;;;;:56;;32533:14;;32549:18;;32512:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;32462:125;32621:15;32637:1;32621:18;;;;;;;;;;;;;;:25;;;32604:42;;32685:15;32701:1;32685:18;;;;;;;;;;;;;;:26;;;32664:47;;32395:441;;;32771:50;32794:15;32810:1;32794:18;;;;;;;;;;;;;;:26;;;32771:18;:22;;:50;;;;:::i;:::-;32750:71;;32395:441;32376:3;;32331:515;;;-1:-1:-1;32859:22:8;;32855:109;;32897:56;;-1:-1:-1;;;32897:56:8;;-1:-1:-1;;;;;32897:20:8;;;;;:56;;32918:14;;32934:18;;32897:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;32855:109;32081:889;;;;:::o;30271:1606::-;30363:39;30422:29;30444:6;30422:21;:29::i;:::-;30418:1453;;;-1:-1:-1;;;;;30480:38:8;;30467:10;30480:38;;;:30;:38;;;;;;30543:8;:15;30576:9;;;;;:35;;-1:-1:-1;30608:3:8;30589:16;:5;30599;30589:16;:9;:16;:::i;:::-;:22;30576:35;30572:96;;;30637:16;:5;30647;30637:16;:9;:16;:::i;:::-;30631:22;;30572:96;30720:14;:3;30728:5;30720:14;:7;:14;:::i;:::-;30699:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;30681:54:8;-1:-1:-1;30762:5:8;30781:1022;30796:3;30788:5;:11;30781:1022;;;30828:16;30847:8;30856:5;30847:15;;;;;;;;;;;;;;;;;;:27;;;30828:46;;30892:10;30905:8;30914:5;30905:15;;;;;;;;;;;;;;;;;;:21;;;30892:34;;30944:13;30960:69;31002:6;31010:11;31023:5;30960:41;:69::i;:::-;30944:85;-1:-1:-1;31051:23:8;30944:85;31072:1;31051:23;:20;:23;:::i;:::-;31047:742;;;-1:-1:-1;;;;;31211:26:8;;;;;;:18;:26;;;;;31263:8;:15;;31098:232;;31211:26;31263:8;31272:5;;31263:15;;;;;;;;;;;;;;31098:232;;;;;;;;31263:15;;;;;;;31098:232;;;;;;;;;;;-1:-1:-1;;;;;31098:37:8;;;;:29;:37;;;;;:50;;;;;;;;;;:232;31324:5;31098:232;:87;:232;:::i;:::-;31352:167;31452:8;31461:5;31452:15;;;;;;;;;;;;;;;;31352:167;;;;;;;;31452:15;;;;;;;31352:167;;;;;;;;;;;-1:-1:-1;;;;;31352:46:8;;;;:38;:46;;;;;:59;;;;;;;;;;31513:5;31352:167;:74;:167;:::i;:::-;31584:6;31541:15;31557:16;:5;31567;31557:16;:9;:16;:::i;:::-;31541:33;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;31541:49:8;;;;;31680:90;31700:69;31742:6;31750:11;31763:5;31700:41;:69::i;:::-;31680:8;;:90;:19;:90;:::i;:::-;31612:15;31628:16;:5;31638;31628:16;:9;:16;:::i;:::-;31612:33;;;;;;;;;;;;;;:41;;:158;;;;;31047:742;30781:1022;;;30801:7;;;;;30781:1022;;;-1:-1:-1;;;;;;31816:38:8;;;;;;:30;:38;;;;;:44;-1:-1:-1;30271:1606:8;;;;:::o;26918:200::-;27022:15;;:42;;-1:-1:-1;;;27022:42:8;;26968:4;;;;-1:-1:-1;;;;;27022:15:8;;;;:27;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26984:81;;27082:11;-1:-1:-1;;;;;27082:27:8;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27075:36;;;26918:200;:::o;7629:884:30:-;7750:29;;:::i;:::-;7819:30;;;;7803:12;:5;7813:1;7803:12;:9;:12;:::i;:::-;:46;;7795:90;;;;-1:-1:-1;;;7795:90:30;;;;;;;;;7899:30;;;;7895:104;;7957:31;7986:1;7957:28;:31::i;:::-;7950:38;;;;7895:104;8008:10;8021:34;8039:8;8049:5;8021:17;:34::i;:::-;8008:47;-1:-1:-1;8069:27:30;8008:47;8094:1;8069:27;:24;:27;:::i;:::-;8065:96;;;8119:31;8148:1;8119:28;:31::i;:::-;8112:38;;;;;8065:96;8186:6;8206:14;;;8202:60;;;-1:-1:-1;8246:5:30;8202:60;8272:49;;:::i;:::-;8336:62;8365:25;:5;8382:7;8365:25;:16;:25;:::i;:::-;8392:5;8336:28;:62::i;:::-;8272:126;;8408:62;8433:8;8443:19;8464:5;8408:24;:62::i;:::-;8487:19;-1:-1:-1;;;7629:884:30;;;;;;:::o;4196:1041::-;4382:30;;;;4366:12;:5;4376:1;4366:12;:9;:12;:::i;:::-;:46;;4358:89;;;;-1:-1:-1;;;4358:89:30;;;;;;;;;4511:31;;;;4478:29;;:64;;4457:141;;;;-1:-1:-1;;;4457:141:30;;;;;;;;;4612:30;;;;4608:72;;4663:7;;4608:72;4689:10;4702:44;4730:8;4740:5;4702:27;:44::i;:::-;4689:57;-1:-1:-1;4760:27:30;4689:57;4785:1;4760:27;:24;:27;:::i;:::-;4756:64;;;4803:7;;;4756:64;4941:31;;;;;4893:29;;;4854:21;;;:14;;;:21;;;;;;;;:119;;:69;;:21;:69;:38;:69;:::i;:::-;:86;:119;:86;:119;:::i;:::-;4830:21;;;;:14;;;:21;;;;;:143;;;;4998:12;4845:5;5008:1;4998:12;:9;:12;:::i;:::-;4989:21;;4984:247;5017:8;:25;;;5012:1;:30;4984:247;;5188:31;;;;;5136:29;;;5090:24;;;:21;;;:24;;;;;;;;:130;;:76;;:24;:76;:45;:76;:::i;:130::-;5063:24;;;;:21;;;;:24;;;;;;:157;;;;5044:3;4984:247;;;;4196:1041;;;;;:::o;29330:935:8:-;29496:14;;;;29492:767;;29531:14;;;;:22;;;29567:13;;;;:21;;;-1:-1:-1;29602:18:8;;;;;;;;;;:52;;;;;;;;;;;;;;;29668:28;;:32;29492:767;;;29756:5;29739:3;:13;;;:22;;29731:72;;;;-1:-1:-1;;;29731:72:8;;;;;;;;;29838:5;29821:3;:13;;;:22;29817:432;;;29924:11;:18;;;;;;;;;;;;:55;;;;;;;;;;;;;;;;;;;:68;;29980:11;29924:68;:55;:68;:::i;:::-;29863:11;:18;;;;;;;;;;;:129;;;;;;;;;;;;29817:432;;;30031:11;:18;;;;;;;;;;;:52;;;;;;;;;;;;30101:28;;;;:32;;;30163:13;;;;;30151:26;;;;:36;:44;;;30213:21;;;29330:935;;;:::o;34986:611::-;35145:15;;:46;;-1:-1:-1;;;35145:46:8;;35079:4;;;;-1:-1:-1;;;;;35145:15:8;;;;:27;;:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;35223:39:8;;35288:1;35223:39;;;:31;:39;;;;;;;;:62;;;:49;;:62;;;;;;35095:97;;-1:-1:-1;35223:66:8;;;:311;;-1:-1:-1;;;;;;35331:39:8;;;;;;:31;:39;;;;;;;;:62;;;:49;;:62;;;;;;:67;:185;;;;;35471:15;-1:-1:-1;;;;;35471:43:8;;:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;35422:39:8;;;;;;:31;:39;;;;;:46;:94;35331:185;35202:388;;;;-1:-1:-1;;;35202:388:8;;;;;;;;21326:704;21567:11;:18;;21612:180;;;;;;;;-1:-1:-1;;;;;21612:180:8;;;;;;;;;;;;;;;;;;;;;;;;21731:3;21612:180;;;;;;-1:-1:-1;21612:180:8;;;;;;;;;;;;;;;;;;21595:198;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;21595:198:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21567:18;;21612:180;;21595:198;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;21803:35:8;;;;:22;:35;;;;;;;;:54;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;21867:27:8;;;;:19;:27;;;;;:46;;;;;;;;;;;;;;;21956:11;:25;;21923:100;;21956:11;21844:12;;21956:25;;;;;;;;;;;;;;;;;;;:32;21990:11;:25;;-1:-1:-1;;;;;21956:32:8;;;;22002:12;;21990:25;;;;;;;;;;;;;;;;:32;;;21923;:100::i;:::-;;21326:704;;;;;;;:::o;25304:244::-;25377:4;25393:17;25413:18;:16;:18::i;:::-;25393:38;;25441:25;25459:6;25441:17;:25::i;:::-;-1:-1:-1;;;;;25483:26:8;;;;;;:18;:26;;;;;:58;;25528:12;25483:58;:44;:58;:::i;24230:468::-;-1:-1:-1;;;;;24339:39:8;;;;;;:31;:39;;;;;;;;:62;;;:49;;;;:62;;;;;;;:67;24335:200;;;-1:-1:-1;;;;;24471:39:8;;;;;;:31;:39;;;;;:46;:53;;24522:1;24471:53;:50;:53;:::i;:::-;-1:-1:-1;;;;;24422:39:8;;;;;;:31;:39;;;;;:102;24335:200;-1:-1:-1;;;;;24622:39:8;;;;;;:31;:39;;;;;;;;:62;;;24689:1;24622:49;;;:62;;;;;;;:69;;;:66;:69;:::i;:::-;-1:-1:-1;;;;;24544:39:8;;;;;;;:31;:39;;;;;;;;:75;;;:62;;;;:75;;;:147;24230:468::o;22036:556::-;22115:4;22131:17;22151:18;:16;:18::i;:::-;22131:38;;22179:12;22194:11;22206:12;22194:25;;;;;;;;;;;;;;;;;;:33;;;22179:48;;22257:7;22242:12;:22;22238:348;;;22287:55;22299:11;22311:12;22299:25;;;;;;;;;;;;;;;;;;:42;;;22287:7;:11;;:55;;;;:::i;:::-;22280:62;;;;;;22238:348;22373:21;22397:73;22427:11;22439:12;22427:25;;;;;;;;;;;;;;;;;;:42;;;22397:25;22414:7;22397:12;:16;;:25;;;;:::i;:73::-;22373:97;;22491:84;22503:71;22531:11;22543:12;22531:25;;;;;;;;;;;;;;;;;;:42;;;22503:23;22524:1;22503:16;:20;;:23;;;;:::i;:::-;:27;:71;:27;:71;:::i;:::-;22491:7;;:84;:11;:84;:::i;:::-;22484:91;;;;;;;28307:1017;28397:4;28431:31;;;:17;:31;;;;;:65;28525:11;:25;;28397:4;;28525:11;28449:12;;28525:25;;;;;;;;;;;;;;;;:37;;;28506:56;;28572:11;28586;28598:12;28586:25;;;;;;;;;;;;;;;;;;:32;;;28572:46;;28632:10;28646:1;28632:15;28628:182;;;28676:32;;;;:19;:32;;;;;:43;;;;-1:-1:-1;28737:15:8;28733:67;;28779:6;-1:-1:-1;28772:13:8;;-1:-1:-1;;28772:13:8;28733:67;28833:10;28819:476;28861:1;28857;:5;:47;;;;;28870:11;28882:12;28870:25;;;;;;;;;;;;;;;;;;:34;;;28866:1;:38;28857:47;28819:476;;;29000:11;29012:12;29000:25;;;;;;;;;;;;;;;;;;:33;;;28995:1;:38;28991:294;;29194:32;;;;:19;:32;;;;;;;;:43;;;;;;;;:75;;;;29094:73;;29062:208;;29194:75;29062:106;;:6;;:31;:106::i;:208::-;29053:217;;28991:294;28922:32;;;;:19;:32;;;;;;;;:43;;;;;;;:53;;;28819:476;;;-1:-1:-1;29311:6:8;28307:1017;-1:-1:-1;;;;28307:1017:8:o;27904:176::-;28006:34;;;;:21;:34;;;;;:67;;28059:6;28067:5;28006:67;:52;:67;:::i;23826:163::-;-1:-1:-1;;;;;23923:26:8;;;;;;:18;:26;;;;;:59;;23968:6;23976:5;23923:59;:44;:59;:::i;23995:229::-;-1:-1:-1;;;;;24134:37:8;;;;;;:29;:37;;;;;;;;:50;;;;;;;;:83;;24203:6;24211:5;24134:83;:68;:83;:::i;2119:459:35:-;2177:7;2418:6;2414:45;;-1:-1:-1;2447:1:35;2440:8;;2414:45;2481:5;;;2485:1;2481;:5;:1;2504:5;;;;;:10;2496:56;;;;-1:-1:-1;;;2496:56:35;;;;;;;;28086:215:8;28206:43;;;;:30;:43;;;;;:88;;28271:15;28288:5;28206:88;:64;:88;:::i;24998:300::-;-1:-1:-1;;;;;25187:46:8;;;;;;:38;:46;;;;;;;;:59;;;;;;;;:104;;25268:15;25285:5;25187:104;:80;:104;:::i;930::5:-;1017:10;930:104;:::o;6523:184:0:-;6596:12;;;;:6;:12;;;;;:33;;6621:7;6596:33;:24;:33;:::i;:::-;6592:109;;;6677:12;:10;:12::i;:::-;-1:-1:-1;;;;;6650:40:0;6668:7;-1:-1:-1;;;;;6650:40:0;6662:4;6650:40;;;;;;;;;;6523:184;;:::o;27767:131:8:-;-1:-1:-1;;;;;27852:29:8;27829:4;27852:29;;;:21;:29;;;;;:35;:39;;;27767:131::o;6713:188:0:-;6787:12;;;;:6;:12;;;;;:36;;6815:7;6787:36;:27;:36;:::i;:::-;6783:112;;;6871:12;:10;:12::i;:::-;-1:-1:-1;;;;;6844:40:0;6862:7;-1:-1:-1;;;;;6844:40:0;6856:4;6844:40;;;;;;;;;;6713:188;;:::o;6052:147:13:-;6126:7;6168:22;6172:3;6184:5;6168:3;:22::i;5368:156::-;5448:4;5471:46;5481:3;-1:-1:-1;;;;;5501:14:13;;5471:9;:46::i;26397:515:8:-;26492:4;26508:17;26528:18;:16;:18::i;:::-;-1:-1:-1;;;;;26577:35:8;;;;;;:27;:35;;;;;:41;;;26508:38;;-1:-1:-1;26577:57:8;;26556:138;;;;-1:-1:-1;;;26556:138:8;;;;;;;;;-1:-1:-1;;;;;26712:35:8;;;;;;:27;:35;;;;;:42;:52;-1:-1:-1;26712:52:8;26704:92;;;;-1:-1:-1;;;26704:92:8;;;;;;;;;-1:-1:-1;;;;;26851:35:8;;;;;;:27;:35;;;;;:42;:54;;26898:6;26851:54;:46;:54;:::i;:::-;-1:-1:-1;;;;;26806:35:8;;;;;;;:27;:35;;;;;:99;;;;26397:515;;-1:-1:-1;;26397:515:8:o;6609:1014:30:-;6743:30;;;;6690:4;;6727:12;:5;6737:1;6727:12;:9;:12;:::i;:::-;:46;;6706:118;;;;-1:-1:-1;;;6706:118:30;;;;;;;;;6838:30;;;;6834:74;;-1:-1:-1;6896:1:30;6889:8;;6834:74;6956:5;6922:8;:30;;;:39;6918:667;;6991:30;;;;6977:539;7028:5;7023:1;:10;6977:539;;7058:13;7125:24;;;:21;;;:24;;;;;;;;;7093:19;;;;;;;7074:14;;;;:76;;7125:24;7074:39;;:14;:39;:18;:39;:::i;:76::-;7058:92;;7190:8;7172;:14;;;:26;7168:98;;7222:14;;;:25;;;7168:98;7309:1;7287:19;;;;;;;;;;;:23;7283:96;;7341:16;:19;;;;;;;;;;7334:26;7283:96;7427:1;7400:24;;;:21;;;:24;;;;;;:28;7396:106;;7459:24;;;;:21;;;:24;;;;;7452:31;7396:106;-1:-1:-1;7035:3:30;;6977:539;;;-1:-1:-1;7562:12:30;:5;7572:1;7562:12;:9;:12;:::i;:::-;7529:30;;;:45;6918:667;-1:-1:-1;;7602:14:30;;;;6609:1014::o;32976:2004:8:-;33129:15;;:54;;-1:-1:-1;;;33129:54:8;;33042:47;;-1:-1:-1;;;;;33129:15:8;;:27;;:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33042:142;;33195:17;33215:18;:16;:18::i;:::-;33195:38;-1:-1:-1;33279:19:8;33195:38;33296:1;33279:19;:16;:19;:::i;:::-;33243:11;33255:12;33243:25;;;;;;;;;;;;;;;;;;:33;;:55;;;;33383:1;33312:19;:58;33332:11;33344:12;33332:25;;;;;;;;;;;;;;;;;;:37;;;33312:58;;;;;;;;;;;:68;;;:72;33308:255;;;33484:19;:58;33504:11;33516:12;33504:25;;;;;;;;;;;;;;;;:37;:25;;;;;:37;;;;;33484:58;;;;;;;;;;;;;;;:68;;;33400:31;;;:17;:31;;;;:152;33308:255;33573:157;33613:11;33625:12;33613:25;;;;;;;;;;;;;;;;;;:37;;;33664:11;33676:12;33664:25;;;;;;;;;;;;;;;;;;:32;;;33710:19;33727:1;33710:12;:16;;:19;;;;:::i;:::-;33573:26;:157::i;:::-;33740:149;33777:11;33789:12;33777:25;;;;;;;;;;;;;;;;;;;;;:32;33823:11;:25;;-1:-1:-1;;;;;33777:32:8;;;;33835:12;;33823:25;;;;;;;;;;;;;;;;:32;;;33869:19;33886:1;33869:12;:16;;:19;;;;:::i;:::-;33740:23;:149::i;:::-;33899:211;33947:11;33959:12;33947:25;;;;;;;;;;;;;;;;;;;;;:32;33993:11;:25;;-1:-1:-1;;;;;33947:32:8;;;;34005:12;;33993:25;;;;;;;;;;;;;;;;:37;;;34044:11;34056:12;34044:25;;;;;;;;;;;;;;;;;;:32;;;34090:19;34107:1;34090:12;:16;;:19;;;;:::i;:::-;33899:34;:211::i;:::-;34120:158;34161:11;34173:12;34161:25;;;;;;;;;;;;;;;;;;;;;:32;34207:11;:25;;-1:-1:-1;;;;;34161:32:8;;;;34219:12;;34207:25;;;;;;;;;;;;;;;;:37;;;34258:19;34275:1;34258:12;:16;;:19;;;;:::i;:::-;34120:27;:158::i;:::-;34288:20;34311:135;34348:23;-1:-1:-1;;;;;34348:40:8;;34402:11;34414:12;34402:25;;;;;;;;;;;;;;;;;;:42;;;34348:97;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34311:11;34323:12;34311:25;;;;;;;;;;;;;;;;;;:32;;;:36;;:135;;;;:::i;:::-;34288:158;;34456:149;34505:11;34517:12;34505:25;;;;;;;;;;;;;;;;;;:37;;;34556:15;34585:19;34602:1;34585:12;:16;;:19;;;;:::i;:::-;34456:35;:149::i;:::-;34615:203;34672:11;34684:12;34672:25;;;;;;;;;;;;;;;;;;;;;:32;34718:11;:25;;-1:-1:-1;;;;;34672:32:8;;;;34730:12;;34718:25;;;;;;;;;;;;;;;;:37;;;34769:15;34798:19;34815:1;34798:12;:16;;:19;;;;:::i;:::-;34615:43;:203::i;:::-;34828:145;34880:11;34892:12;34880:25;;;;;;;;;;;;;;;;;;;;;:32;34926:11;:25;;-1:-1:-1;;;;;34880:32:8;;;;34938:12;;34926:25;;;;;;;;;;;;;;;;:37;;;34828:38;:145::i;1409:498:23:-;1820:4;1864:17;1895:7;1409:498;:::o;2850:248:31:-;1024:12:23;;;;;;;;:31;;;1040:15;:13;:15::i;:::-;1024:47;;;-1:-1:-1;1060:11:23;;;;1059:12;1024:47;1016:106;;;;-1:-1:-1;;;1016:106:23;;;;;;;;;1129:19;1152:12;;;;;;1151:13;1170:80;;;;1198:12;:19;;-1:-1:-1;;;;1198:19:23;;;;;1225:18;1213:4;1225:18;;;1170:80;2939:47:31::1;:45;:47::i;:::-;2996:42;1803:4:0;3027:10:31;2996;:42::i;:::-;3048:43;3068:22;3048:19;:43::i;5605:115:13:-:0;5668:7;5694:19;5702:3;5694:7;:19::i;25554:256:8:-;-1:-1:-1;;;;;25728:37:8;;25701:4;25728:37;;;:29;:37;;;;;;;;:50;;;;;;;;:75;;25797:5;25728:75;:68;:75;:::i;:::-;25721:82;25554:256;-1:-1:-1;;;;25554:256:8:o;834:176:35:-;892:7;923:5;;;946:6;;;;938:46;;;;-1:-1:-1;;;938:46:35;;;;;;;;1274:134;1332:7;1358:43;1362:1;1365;1358:43;;;;;;;;;;;;;;;;;:3;:43::i;988:212:25:-;1048:7;1076:1;1071;:6;1067:127;;-1:-1:-1;1100:5:25;;;1093:12;;1067:127;1141:20;1156:1;1159;1141:20;;;;;;;;;;;;;;;;-1:-1:-1;1182:1:25;1175:8;;1402:145;1468:4;-1:-1:-1;;1491:19:25;-1:-1:-1;1484:27:25;;;;-1:-1:-1;978:3:25;1532:8;-1:-1:-1;1528:12:25;1402:145::o;8869:385:30:-;9085:162;9143:8;9165:11;9190:19;9223:5;9242:4;9085:44;:162::i;1344:124:15:-;1403:15;;:::i;:::-;1437:24;1452:5;1459:1;1437:14;:24::i;1553:200:25:-;1626:4;1650:1;1646;:5;1642:105;;;-1:-1:-1;978:3:25;1674:5;;;:12;1667:19;;1642:105;-1:-1:-1;978:3:25;1724:5;;;:12;1717:19;;1025:313:15;1106:15;;:::i;:::-;1155:1;1141:11;:15;1133:44;;;;-1:-1:-1;;;1133:44:15;;;;;;;;;1187:24;;:::i;:::-;1214:58;;;;;;;;1235:9;1214:58;;;;1259:11;1214:58;;;1187:85;;1282:24;1297:8;1282:14;:24::i;8519:344:30:-;8696:160;8754:8;8776;8798:19;8831:5;8850;8696:44;:160::i;3033:130:35:-;3091:7;3117:39;3121:1;3124;3117:39;;;;;;;;;;;;;;;;;:3;:39::i;1740:206:15:-;1827:15;;:::i;:::-;1892:11;;1876;;1861:78;;1876:28;;:11;:28;:15;:28;:::i;:::-;1924:13;;;;;1906;;;;:32;;;:17;:32;:::i;:::-;1861:14;:78::i;25816:575:8:-;25904:4;25920:17;25940:18;:16;:18::i;:::-;-1:-1:-1;;;;;25972:35:8;;;;;;:27;:35;;;;;:41;;;25920:38;;-1:-1:-1;25972:56:8;-1:-1:-1;25968:417:8;;;-1:-1:-1;;;;;26044:35:8;;;;;;:27;:35;;;;;:51;;;26109:41;;:56;;;25968:417;;;-1:-1:-1;;;;;26203:35:8;;;;;;:27;:35;;;;;:41;;;:57;;26196:65;;;;-1:-1:-1;;;;;26320:35:8;;;;;;:27;:35;;;;;:42;:54;;26367:6;26320:54;:46;:54;:::i;5921:682:30:-;6056:12;:5;6066:1;6056:12;:9;:12;:::i;:::-;6022:8;:30;;;:46;;6014:88;;;;-1:-1:-1;;;6014:88:30;;;;;;;;;6116:30;;;;6112:151;;6167:30;;;:38;;;6219:25;;;:33;;;6112:151;6284:8;:25;;;6276:5;:33;6272:97;;;6325:25;;;:33;;;6272:97;6392:8;:30;;;6383:5;:39;6379:218;;6469:28;;;;:21;;;:28;;;;;;:38;;6502:4;6469:38;:32;:38;:::i;:::-;6438:28;;;;:21;;;:28;;;;;:69;6379:218;;;6555:14;;;;:31;;6581:4;6555:31;:25;:31;:::i;:::-;6538:14;;;:48;5921:682;;;:::o;2773:486::-;2914:5;2880:8;:30;;;:39;;2872:81;;;;-1:-1:-1;;;2872:81:30;;;;;;;;;2967:30;;;;2963:104;;3018:30;;;:38;;;2963:104;3107:28;;;;:21;;;:28;;;;;;:38;;3140:4;3107:38;:32;:38;:::i;:::-;3076:28;;;;:21;;;:28;;;;;:69;3159:25;;;;:34;;3155:98;;3209:25;;;:33;;;2773:486;;;:::o;4831:141:13:-;4901:4;4924:41;4929:3;-1:-1:-1;;;;;4949:14:13;;4924:4;:41::i;5140:147::-;5213:4;5236:44;5244:3;-1:-1:-1;;;;;5264:14:13;;5236:7;:44::i;4390:201::-;4484:18;;4457:7;;4484:26;-1:-1:-1;4476:73:13;;;;-1:-1:-1;;;4476:73:13;;;;;;;;;4566:3;:11;;4578:5;4566:18;;;;;;;;;;;;;;;;4559:25;;4390:201;;;;:::o;3743:127::-;3816:4;3839:19;;;:12;;;;;:19;;;;;;:24;;;3743:127::o;22598:164:8:-;22695:34;;;;:21;:34;;;;;:60;;22741:6;22749:5;22695:60;:45;:60;:::i;22977:151::-;-1:-1:-1;;;;;23069:26:8;;;;;;:18;:26;;;;;:52;;23107:6;23115:5;23069:52;:37;:52;:::i;23134:217::-;-1:-1:-1;;;;;23268:37:8;;;;;;:29;:37;;;;;;;;:50;;;;;;;;:76;;23330:6;23338:5;23268:76;:61;:76;:::i;27309:452::-;-1:-1:-1;;;;;27414:29:8;;;;;;:21;:29;;;;;:35;27410:184;;-1:-1:-1;;;;;27470:29:8;;;;;;:21;:29;;;;;;;;:43;;;27568:8;:15;27527:30;:38;;;;;;:56;27410:184;-1:-1:-1;;;;;27607:29:8;;;;;;:21;:29;;;;;;;;:54;;;:41;;:54;;;;;;27603:152;;-1:-1:-1;;;;;27682:29:8;;;;;;;;:21;:29;;;;;;;;:54;;;:41;;;;:54;;;:62;27309:452::o;22768:203::-;22883:43;;;;:30;:43;;;;;:81;;22941:15;22958:5;22883:81;:57;:81;:::i;24704:288::-;-1:-1:-1;;;;;24888:46:8;;;;;;:38;:46;;;;;;;;:59;;;;;;;;:97;;24962:15;24979:5;24888:97;:73;:97;:::i;23357:463::-;-1:-1:-1;;;;;23461:39:8;;;;;;:31;:39;;;;;;;;:62;;;:49;;:62;;;;;;23457:200;;-1:-1:-1;;;;;23593:39:8;;;;;;:31;:39;;;;;:46;:53;;23644:1;23593:53;:50;:53;:::i;:::-;-1:-1:-1;;;;;23544:39:8;;;;;;:31;:39;;;;;:102;23457:200;-1:-1:-1;;;;;23744:39:8;;;;;;:31;:39;;;;;;;;:62;;;23811:1;23744:49;;;:62;;;;;;;:69;;;:66;:69;:::i;1301:138:0:-;1024:12:23;;;;;;;;:31;;;1040:15;:13;:15::i;:::-;1024:47;;;-1:-1:-1;1060:11:23;;;;1059:12;1024:47;1016:106;;;;-1:-1:-1;;;1016:106:23;;;;;;;;;1129:19;1152:12;;;;;;1151:13;1170:80;;;;1198:12;:19;;-1:-1:-1;;;;1198:19:23;;;;;1225:18;1213:4;1225:18;;;1170:80;1364:26:0::1;:24;:26::i;:::-;1400:32;:30;:32::i;:::-;1268:14:23::0;1264:55;;;1307:5;1292:20;;-1:-1:-1;;1292:20:23;;;1301:138:0;:::o;3704:317:31:-;-1:-1:-1;;;;;3791:36:31;;3783:83;;;;-1:-1:-1;;;3783:83:31;;;;;;;;;3884:35;:22;-1:-1:-1;;;;;3884:33:31;;:35::i;:::-;3876:71;;;;-1:-1:-1;;;3876:71:31;;;;;;;;;3957:15;:57;;-1:-1:-1;;;;;;3957:57:31;-1:-1:-1;;;;;3957:57:31;;;;;;;;;;3704:317::o;3951:107:13:-;4033:18;;3951:107::o;1692:187:35:-;1778:7;1813:12;1805:6;;;;1797:29;;;;-1:-1:-1;;;1797:29:35;;;;;;;;;;-1:-1:-1;;;1848:5:35;;;1692:187::o;9260:1629:30:-;9537:30;;;;9521:12;:5;9531:1;9521:12;:9;:12;:::i;:::-;:46;;9513:90;;;;-1:-1:-1;;;9513:90:30;;;;;;;;;9617:14;9613:138;;;9671:33;;;;9655:12;:5;9665:1;9655:12;:9;:12;:::i;:::-;:49;;9647:93;;;;-1:-1:-1;;;9647:93:30;;;;;;;;;9814:31;;;;9781:29;;:64;;9760:141;;;;-1:-1:-1;;;9760:141:30;;;;;;;;;9915:30;;;;9911:72;;9966:7;;9911:72;9992:10;10005:34;10023:8;10033:5;10005:17;:34::i;:::-;9992:47;-1:-1:-1;10053:27:30;9992:47;10078:1;10053:27;:24;:27;:::i;:::-;10049:64;;;10096:7;;;10049:64;10123:13;10139:86;10193:19;:31;;;10139:49;10158:19;:29;;;10139:8;:14;;;:18;;:49;;;;:::i;:86::-;10123:102;;10239:14;10235:119;;;10269:74;10287:11;10300:35;10326:8;10300;:14;;;:25;;:35;;;;:::i;:::-;10337:5;10269:17;:74::i;:::-;10363:14;;;:25;;;10404:6;10413:12;:5;10423:1;10413:12;:9;:12;:::i;:::-;10404:21;;10399:484;10432:8;:25;;;10427:1;:30;10399:484;;10591:31;;;;;10539:29;;10478:12;10493:24;;;:21;;;:24;;;;;;;:130;;10591:31;10493:76;;:24;:76;:45;:76;:::i;:130::-;10478:145;;10641:14;10637:188;;;10765:24;;;;:21;;;:24;;;;;;10705:105;;10765:44;;10801:7;10765:44;:35;:44;:::i;:::-;10705:27;;;;:24;;;:27;;;;;;;:105;:59;:105;:::i;:::-;10675:27;;;;:24;;;:27;;;;;:135;10637:188;10838:24;;;;:21;;;;:24;;;;;;:34;;;;10459:3;10399:484;;1474:260:15;1548:9;1560:45;1564:8;:18;;;1584:8;:20;;;1560:3;:45::i;:::-;1636:18;;1548:57;;-1:-1:-1;1636:28:15;;1548:57;1636:28;:22;:28;:::i;:::-;1615:49;;1697:20;;;;:30;;1722:4;1697:30;:24;:30;:::i;:::-;1674:20;;;;:53;;;;-1:-1:-1;1474:260:15:o;3638:338:35:-;3724:7;3824:12;3817:5;3809:28;;;;-1:-1:-1;;;3809:28:35;;;;;;;;;;;3847:9;3863:1;3859;:5;;;;;;;3638:338;-1:-1:-1;;;;;3638:338:35:o;1578:404:13:-;1641:4;1662:21;1672:3;1677:5;1662:9;:21::i;:::-;1657:319;;-1:-1:-1;1699:23:13;;;;;;;;:11;:23;;;;;;;;;;;;;1879:18;;1857:19;;;:12;;;:19;;;;;;:40;;;;1911:11;;1657:319;-1:-1:-1;1960:5:13;1953:12;;2150:1512;2216:4;2353:19;;;:12;;;:19;;;;;;2387:15;;2383:1273;;2816:18;;-1:-1:-1;;2768:14:13;;;;2816:22;;;;2744:21;;2816:3;;:22;;3098;;;;;;;;;;;;;;3078:42;;3241:9;3212:3;:11;;3224:13;3212:26;;;;;;;;;;;;;;;;;;;:38;;;;3316:23;;;3358:1;3316:12;;;:23;;;;;;3342:17;;;3316:43;;3465:17;;3316:3;;3465:17;;;;;;;;;;;;;;;;;;;;;;3557:3;:12;;:19;3570:5;3557:19;;;;;;;;;;;3550:26;;;3598:4;3591:11;;;;;;;;2383:1273;3640:5;3633:12;;;;;5271:644:30;5399:5;5365:8;:30;;;:39;;5357:74;;;;-1:-1:-1;;;5357:74:30;;;;;;;;;5445:30;;;;5441:151;;5496:30;;;:38;;;5548:25;;;:33;;;5441:151;5613:8;:25;;;5605:5;:33;5601:97;;;5654:25;;;:33;;;5601:97;5721:8;:30;;;5712:5;:39;5708:201;;5793:16;:23;;;;;;;;;;;:33;;5821:4;5793:33;:27;:33;:::i;:::-;5767:16;:23;;;;;;;;;;:59;5708:201;;;5874:14;;;;:24;;5893:4;5874:24;:18;:24;:::i;2305:462::-;2439:5;2405:8;:30;;;:39;;2397:74;;;;-1:-1:-1;;;2397:74:30;;;;;;;;;2485:30;;;;2481:104;;2536:30;;;:38;;;2481:104;2620:16;:23;;;;;;;;;;;:33;;2648:4;2620:33;:27;:33;:::i;:::-;2594:16;:23;;;;;;;;;;:59;2667:25;;;;:34;;2663:98;;2717:25;;;:33;;;2305:462;;;:::o;857:66:5:-;1024:12:23;;;;;;;;:31;;;1040:15;:13;:15::i;:::-;1024:47;;;-1:-1:-1;1060:11:23;;;;1059:12;1024:47;1016:106;;;;-1:-1:-1;;;1016:106:23;;;;;;;;;1129:19;1152:12;;;;;;1151:13;1170:80;;;;1198:12;:19;;-1:-1:-1;;;;1198:19:23;;;;;1225:18;1213:4;1225:18;;;1268:14;1264:55;;;1307:5;1292:20;;-1:-1:-1;;1292:20:23;;;857:66:5;:::o;685:610:1:-;745:4;1206:20;;1051:66;1245:23;;;;;;:42;;-1:-1:-1;;1272:15:1;;;1237:51;-1:-1:-1;;685:610:1:o;1952:298:15:-;2004:4;2030:1;2051;2066:7;;;2062:61;;;2100:12;2105:2;2109;2100:4;:12::i;:::-;2089:23;;-1:-1:-1;2089:23:15;-1:-1:-1;2062:61:15;2139:6;;2132:93;;2166:10;:2;2173;2166:10;:6;:10;:::i;:::-;2161:15;;2201:13;2207:2;2211;2201:4;:13::i;:::-;2190:24;;-1:-1:-1;2190:24:15;-1:-1:-1;2132:93:15;;;-1:-1:-1;2241:2:15;1952:298;-1:-1:-1;;;1952:298:15:o;2256:95::-;2339:1;2256:95::o;4420:128:35:-;4478:7;4504:37;4508:1;4511;4504:37;;;;;;;;;;;;;;;;;5098:7;5133:12;5125:6;5117:29;;;;-1:-1:-1;;;5117:29:35;;;;;;;;;;;5167:1;5163;:5;;;;;;;5012:163;-1:-1:-1;;;;5012:163:35:o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;1193:241;;1297:2;1285:9;1276:7;1272:23;1268:32;1265:2;;;-1:-1;;1303:12;1265:2;85:6;72:20;97:33;124:5;97:33;;1441:263;;1556:2;1544:9;1535:7;1531:23;1527:32;1524:2;;;-1:-1;;1562:12;1524:2;226:6;220:13;238:33;265:5;238:33;;1711:366;;;1832:2;1820:9;1811:7;1807:23;1803:32;1800:2;;;-1:-1;;1838:12;1800:2;85:6;72:20;97:33;124:5;97:33;;;1890:63;1990:2;2029:22;;;;982:20;;-1:-1;;;1794:283;2084:491;;;;2222:2;2210:9;2201:7;2197:23;2193:32;2190:2;;;-1:-1;;2228:12;2190:2;85:6;72:20;97:33;124:5;97:33;;;2280:63;2380:2;2419:22;;982:20;;-1:-1;2488:2;2527:22;;;982:20;;2184:391;-1:-1;;;2184:391;2582:257;;2694:2;2682:9;2673:7;2669:23;2665:32;2662:2;;;-1:-1;;2700:12;2662:2;364:6;358:13;52415:5;50448:13;50441:21;52393:5;52390:32;52380:2;;-1:-1;;52426:12;2846:241;;2950:2;2938:9;2929:7;2925:23;2921:32;2918:2;;;-1:-1;;2956:12;2918:2;-1:-1;485:20;;2912:175;-1:-1;2912:175;3094:366;;;3215:2;3203:9;3194:7;3190:23;3186:32;3183:2;;;-1:-1;;3221:12;3183:2;498:6;485:20;3273:63;;3373:2;3416:9;3412:22;72:20;97:33;124:5;97:33;;;3381:63;;;;3177:283;;;;;;3467:366;;;3588:2;3576:9;3567:7;3563:23;3559:32;3556:2;;;-1:-1;;3594:12;3556:2;-1:-1;;485:20;;;3746:2;3785:22;;;982:20;;-1:-1;3550:283;4088:263;;4203:2;4191:9;4182:7;4178:23;4174:32;4171:2;;;-1:-1;;4209:12;4171:2;-1:-1;1130:13;;4165:186;-1:-1;4165:186;4731:743;;;;;;4906:3;4894:9;4885:7;4881:23;4877:33;4874:2;;;-1:-1;;4913:12;4874:2;995:6;982:20;4965:63;;5065:2;5108:9;5104:22;982:20;5073:63;;5173:2;5216:9;5212:22;982:20;5181:63;;5309:2;5298:9;5294:18;5281:32;5333:18;;5325:6;5322:30;5319:2;;;-1:-1;;5355:12;5319:2;5441:6;5430:9;5426:22;685:3;678:4;670:6;666:17;662:27;652:2;;-1:-1;;693:12;652:2;736:6;723:20;713:30;;5333:18;755:6;752:30;749:2;;;-1:-1;;785:12;749:2;880:3;5065:2;860:17;821:6;846:32;;843:41;840:2;;;-1:-1;;887:12;840:2;5065;821:6;817:17;5383:75;;;;;;;;4868:606;;;;;;;;;6421:327;;6556:5;49755:12;49902:6;49897:3;49890:19;6640:52;6685:6;49939:4;49934:3;49930:14;49939:4;6666:5;6662:16;6640:52;;;52081:7;52065:14;-1:-1;;52061:28;6704:39;;;;49939:4;6704:39;;6503:245;-1:-1;;6503:245;25247:275;;7272:5;49755:12;7384:52;7429:6;7424:3;7417:4;7410:5;7406:16;7384:52;;;7448:16;;;;;25383:139;-1:-1;;25383:139;25529:222;-1:-1;;;;;50748:54;;;;5691:37;;25656:2;25641:18;;25627:124;26003:349;-1:-1;;;;;50748:54;;;;5560:58;;26338:2;26323:18;;6042:37;26166:2;26151:18;;26137:215;26699:444;-1:-1;;;;;50748:54;;;;5691:37;;27046:2;27031:18;;6042:37;;;;27129:2;27114:18;;6042:37;26882:2;26867:18;;26853:290;27150:556;-1:-1;;;;;50748:54;;;;5691:37;;27526:2;27511:18;;6042:37;;;;27609:2;27594:18;;6042:37;27692:2;27677:18;;6042:37;27361:3;27346:19;;27332:374;27713:1092;;28056:3;5333:18;;50759:42;;;50364:5;50748:54;5698:3;5691:37;6072:5;28221:2;28210:9;28206:18;6042:37;6072:5;28304:2;28293:9;28289:18;6042:37;6072:5;28387:2;28376:9;28372:18;6042:37;6072:5;28470:3;28459:9;28455:19;6042:37;6072:5;28554:3;28543:9;28539:19;6042:37;6072:5;28638:3;28627:9;28623:19;6042:37;28056:3;28676;28665:9;28661:19;28654:49;28717:78;28056:3;28045:9;28041:19;28781:6;28717:78;;;28709:86;28027:778;-1:-1;;;;;;;;;;;28027:778;28812:210;50448:13;;50441:21;5925:34;;28933:2;28918:18;;28904:118;29029:222;6042:37;;;29156:2;29141:18;;29127:124;29535:238;29670:2;29655:18;;52181:1;52171:12;;52161:2;;52187:9;52161:2;6351:58;;;29641:132;;29780:310;;29927:2;29948:17;29941:47;30002:78;29927:2;29916:9;29912:18;30066:6;30002:78;;30097:416;30297:2;30311:47;;;7701:2;30282:18;;;49890:19;7737:34;49930:14;;;7717:55;-1:-1;;;7792:12;;;7785:40;7844:12;;;30268:245;30520:416;30720:2;30734:47;;;8095:2;30705:18;;;49890:19;8131:34;49930:14;;;8111:55;-1:-1;;;8186:12;;;8179:26;8224:12;;;30691:245;30943:416;31143:2;31157:47;;;8475:2;31128:18;;;49890:19;8511:34;49930:14;;;8491:55;-1:-1;;;8566:12;;;8559:39;8617:12;;;31114:245;31366:416;31566:2;31580:47;;;8868:2;31551:18;;;49890:19;8904:33;49930:14;;;8884:54;8957:12;;;31537:245;31789:416;31989:2;32003:47;;;9208:1;31974:18;;;49890:19;-1:-1;;;49930:14;;;9223:31;9273:12;;;31960:245;32212:416;32412:2;32426:47;;;9524:2;32397:18;;;49890:19;9560:34;49930:14;;;9540:55;-1:-1;;;9615:12;;;9608:31;9658:12;;;32383:245;32635:416;32835:2;32849:47;;;9909:2;32820:18;;;49890:19;9945:34;49930:14;;;9925:55;-1:-1;;;10000:12;;;9993:32;10044:12;;;32806:245;33058:416;33258:2;33272:47;;;10295:2;33243:18;;;49890:19;10331:34;49930:14;;;10311:55;10400:26;10386:12;;;10379:48;10446:12;;;33229:245;33481:416;33681:2;33695:47;;;10697:2;33666:18;;;49890:19;-1:-1;;;49930:14;;;10713:38;10770:12;;;33652:245;33904:416;34104:2;34118:47;;;11021:2;34089:18;;;49890:19;11057:34;49930:14;;;11037:55;-1:-1;;;11112:12;;;11105:45;11169:12;;;34075:245;34327:416;34527:2;34541:47;;;11420:2;34512:18;;;49890:19;11456:29;49930:14;;;11436:50;11505:12;;;34498:245;34750:416;34950:2;34964:47;;;11756:2;34935:18;;;49890:19;-1:-1;;;49930:14;;;11772:45;11836:12;;;34921:245;35173:416;35373:2;35387:47;;;12087:2;35358:18;;;49890:19;-1:-1;;;49930:14;;;12103:34;12156:12;;;35344:245;35596:416;35796:2;35810:47;;;12407:2;35781:18;;;49890:19;-1:-1;;;49930:14;;;12423:40;12482:12;;;35767:245;36019:416;36219:2;36233:47;;;12733:2;36204:18;;;49890:19;12769:34;49930:14;;;12749:55;-1:-1;;;12824:12;;;12817:26;12862:12;;;36190:245;36442:416;36642:2;36656:47;;;13113:2;36627:18;;;49890:19;13149:34;49930:14;;;13129:55;-1:-1;;;13204:12;;;13197:26;13242:12;;;36613:245;36865:416;37065:2;37079:47;;;13493:2;37050:18;;;49890:19;13529:32;49930:14;;;13509:53;13581:12;;;37036:245;37288:416;37488:2;37502:47;;;13832:2;37473:18;;;49890:19;13868:34;49930:14;;;13848:55;-1:-1;;;13923:12;;;13916:40;13975:12;;;37459:245;37711:416;37911:2;37925:47;;;14226:2;37896:18;;;49890:19;14262:29;49930:14;;;14242:50;14311:12;;;37882:245;38134:416;38334:2;38348:47;;;14562:2;38319:18;;;49890:19;14598:34;49930:14;;;14578:55;-1:-1;;;14653:12;;;14646:35;14700:12;;;38305:245;38557:416;38757:2;38771:47;;;38742:18;;;49890:19;14987:34;49930:14;;;14967:55;15041:12;;;38728:245;38980:416;39180:2;39194:47;;;15292:2;39165:18;;;49890:19;-1:-1;;;49930:14;;;15308:33;15360:12;;;39151:245;39403:416;39603:2;39617:47;;;15611:2;39588:18;;;49890:19;15647:29;49930:14;;;15627:50;15696:12;;;39574:245;39826:416;40026:2;40040:47;;;15947:2;40011:18;;;49890:19;15983:34;49930:14;;;15963:55;-1:-1;;;16038:12;;;16031:44;16094:12;;;39997:245;40249:416;40449:2;40463:47;;;16345:2;40434:18;;;49890:19;16381:34;49930:14;;;16361:55;-1:-1;;;16436:12;;;16429:25;16473:12;;;40420:245;40672:416;40872:2;40886:47;;;16724:2;40857:18;;;49890:19;16760:25;49930:14;;;16740:46;16805:12;;;40843:245;41095:416;41295:2;41309:47;;;17056:2;41280:18;;;49890:19;-1:-1;;;49930:14;;;17072:39;17130:12;;;41266:245;41518:416;41718:2;41732:47;;;17381:2;41703:18;;;49890:19;17417:31;49930:14;;;17397:52;17468:12;;;41689:245;41941:416;42141:2;42155:47;;;17719:2;42126:18;;;49890:19;17755:25;49930:14;;;17735:46;17800:12;;;42112:245;42364:416;42564:2;42578:47;;;18051:2;42549:18;;;49890:19;18087:34;49930:14;;;18067:55;-1:-1;;;18142:12;;;18135:29;18183:12;;;42535:245;42787:416;42987:2;43001:47;;;18434:2;42972:18;;;49890:19;18470:34;49930:14;;;18450:55;-1:-1;;;18525:12;;;18518:38;18575:12;;;42958:245;43210:416;43410:2;43424:47;;;18826:2;43395:18;;;49890:19;-1:-1;;;49930:14;;;18842:33;18894:12;;;43381:245;43633:416;43833:2;43847:47;;;19145:2;43818:18;;;49890:19;19181:34;49930:14;;;19161:55;-1:-1;;;19236:12;;;19229:26;19274:12;;;43804:245;44056:416;44256:2;44270:47;;;19525:2;44241:18;;;49890:19;19561:34;49930:14;;;19541:55;19630:28;19616:12;;;19609:50;19678:12;;;44227:245;44479:416;44679:2;44693:47;;;19929:2;44664:18;;;49890:19;19965:34;49930:14;;;19945:55;-1:-1;;;20020:12;;;20013:31;20063:12;;;44650:245;44902:416;45102:2;45116:47;;;20314:2;45087:18;;;49890:19;20350:34;49930:14;;;20330:55;-1:-1;;;20405:12;;;20398:29;20446:12;;;45073:245;45325:416;45525:2;45539:47;;;20697:2;45510:18;;;49890:19;20733:34;49930:14;;;20713:55;20802:32;20788:12;;;20781:54;20854:12;;;45496:245;45748:416;45948:2;45962:47;;;21105:2;45933:18;;;49890:19;21141:34;49930:14;;;21121:55;-1:-1;;;21196:12;;;21189:41;21249:12;;;45919:245;46171:416;46371:2;46385:47;;;21500:2;46356:18;;;49890:19;21536:27;49930:14;;;21516:48;21583:12;;;46342:245;46594:416;46794:2;46808:47;;;21834:2;46779:18;;;49890:19;21870:34;49930:14;;;21850:55;-1:-1;;;21925:12;;;21918:33;21970:12;;;46765:245;47017:416;47217:2;47231:47;;;22221:2;47202:18;;;49890:19;22257:27;49930:14;;;22237:48;22304:12;;;47188:245;47440:416;47640:2;47654:47;;;22555:2;47625:18;;;49890:19;22591:32;49930:14;;;22571:53;22643:12;;;47611:245;47863:416;48063:2;48077:47;;;22894:2;48048:18;;;49890:19;-1:-1;;;49930:14;;;22910:39;22968:12;;;48034:245;48286:416;48486:2;48500:47;;;23219:2;48471:18;;;49890:19;23255:34;49930:14;;;23235:55;-1:-1;;;23310:12;;;23303:39;23361:12;;;48457:245;48709:382;;48892:2;48913:17;48906:47;5333:18;;50759:42;;;23707:16;23701:23;50748:54;48892:2;48881:9;48877:18;5691:37;48892:2;23872:5;23868:16;23862:23;23939:14;48881:9;23939:14;6042:37;23939:14;24028:5;24024:16;24018:23;24095:14;48881:9;24095:14;6042:37;24095:14;24194:5;24190:16;24184:23;24261:14;48881:9;24261:14;6042:37;24261:14;24351:5;24347:16;24341:23;24418:14;48881:9;24418:14;6042:37;24418:14;24508:5;24504:16;24498:23;24575:14;48881:9;24575:14;6042:37;24575:14;24666:5;24662:16;24656:23;24733:14;48881:9;24733:14;6042:37;24733:14;24820:5;24816:16;24810:23;23631:6;;;48881:9;24853:14;24846:38;;24899:73;23622:16;48881:9;23622:16;24953:12;24899:73;;49327:333;6042:37;;;49646:2;49631:18;;6042:37;49482:2;49467:18;;49453:207;51721:268;51786:1;51793:101;51807:6;51804:1;51801:13;51793:101;;;51874:11;;;51868:18;51855:11;;;51848:39;51829:2;51822:10;51793:101;;;51909:6;51906:1;51903:13;51900:2;;;-1:-1;;51786:1;51956:16;;51949:27;51770:219;52210:117;-1:-1;;;;;50748:54;;52269:35;;52259:2;;52318:1;;52308:12
Swarm Source
ipfs://88c330383e3eca2d1dd22b553b5b109eafd04aa92a00d266c363bddb03bdaf00
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 29 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.