Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Multichain Info
No addresses found
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
DelegationController
Compiler Version
v0.6.10+commit.00c0fcaf
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input 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 "@openzeppelin/contracts-ethereum-package/contracts/token/ERC777/IERC777.sol"; import "../BountyV2.sol"; import "../Nodes.sol"; import "../Permissions.sol"; import "../utils/FractionUtils.sol"; import "../utils/MathUtils.sol"; import "./DelegationPeriodManager.sol"; import "./PartialDifferences.sol"; import "./Punisher.sol"; import "./TokenLaunchLocker.sol"; import "./TokenState.sol"; import "./ValidatorService.sol"; /** * @title Delegation Controller * @dev This contract performs all delegation functions including delegation * requests, and undelegation, etc. * * Delegators and validators may both perform delegations. Validators who perform * delegations to themselves are effectively self-delegating or self-bonding. * * IMPORTANT: Undelegation may be requested at any time, but undelegation is only * performed at the completion of the current delegation period. * * 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; uint public constant UNDELEGATION_PROHIBITION_WINDOW_SECONDS = 3 * 24 * 60 * 60; 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"); _; } /** * @dev Update and return a validator's delegations. */ function getAndUpdateDelegatedToValidatorNow(uint validatorId) external returns (uint) { return _getAndUpdateDelegatedToValidator(validatorId, _getCurrentMonth()); } /** * @dev Update and return the amount delegated. */ function getAndUpdateDelegatedAmount(address holder) external returns (uint) { return _getAndUpdateDelegatedByHolder(holder); } /** * @dev Update and return the effective amount delegated (minus slash) for * the given month. */ 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. * * Emits a {DelegationProposed} event. * * Requirements: * * - Holder must have sufficient delegatable tokens. * - Delegation must be above the validator's minimum delegation amount. * - Delegation period must be allowed. * - Validator must be authorized if trusted list is enabled. * - Validator must be accepting new delegation requests. */ function delegate( uint validatorId, uint amount, uint delegationPeriod, string calldata info ) external { require( _getDelegationPeriodManager().isDelegationPeriodAllowed(delegationPeriod), "This delegation period is not allowed"); _getValidatorService().checkValidatorCanReceiveDelegation(validatorId, amount); _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 = IERC777(contractManager.getSkaleToken()).balanceOf(msg.sender); uint forbiddenForDelegation = TokenState(contractManager.getTokenState()) .getAndUpdateForbiddenForDelegationAmount(msg.sender); require(holderBalance >= forbiddenForDelegation, "Token holder does not have enough tokens to delegate"); emit DelegationProposed(delegationId); _sendSlashingSignals(slashingSignals); } /** * @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); } /** * @dev Allows token holder to cancel a delegation proposal. * * Emits a {DelegationRequestCanceledByUser} event. * * Requirements: * * - `msg.sender` must be the token holder of the delegation proposal. * - Delegation state must be PROPOSED. */ 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. * * Requirements: * * - Validator must be recipient of proposal. * - Delegation state must be PROPOSED. */ function acceptPendingDelegation(uint delegationId) external checkDelegationExists(delegationId) { require( _getValidatorService().checkValidatorAddressToId(msg.sender, delegations[delegationId].validatorId), "No permissions to accept request"); _accept(delegationId); } /** * @dev Allows delegator to undelegate a specific delegation. * * Emits UndelegationRequested event. * * Requirements: * * - `msg.sender` must be the delegator. * - Delegation state must be DELEGATED. */ function requestUndelegation(uint delegationId) external checkDelegationExists(delegationId) { require(getState(delegationId) == State.DELEGATED, "Cannot request undelegation"); ValidatorService validatorService = _getValidatorService(); require( delegations[delegationId].holder == msg.sender || (validatorService.validatorAddressExists(msg.sender) && delegations[delegationId].validatorId == validatorService.getValidatorId(msg.sender)), "Permission denied to request undelegation"); _removeValidatorFromValidatorsPerDelegators( delegations[delegationId].holder, delegations[delegationId].validatorId); processAllSlashes(msg.sender); delegations[delegationId].finished = _calculateDelegationEndMonth(delegationId); require( now.add(UNDELEGATION_PROHIBITION_WINDOW_SECONDS) < _getTimeHelpers().monthToTimestamp(delegations[delegationId].finished), "Undelegation requests must be sent 3 days before the end of delegation period" ); _subtractFromAllStatistics(delegationId); emit UndelegationRequested(delegationId); } /** * @dev Allows Punisher contract to slash an `amount` of stake from * a validator. This slashes an amount of delegations of the validator, * which reduces the amount that the validator has staked. This consequence * may force the SKALE Manager to reduce the number of nodes a validator is * operating so the validator can meet the Minimum Staking Requirement. * * Emits a {SlashingEvent}. * * See {Punisher}. */ function confiscate(uint validatorId, uint amount) external allow("Punisher") { uint currentMonth = _getCurrentMonth(); FractionUtils.Fraction memory coefficient = _delegatedToValidator[validatorId].reduceValue(amount, currentMonth); uint initialEffectiveDelegated = _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(currentMonth); uint[] memory initialSubtractions = new uint[](0); if (currentMonth < _effectiveDelegatedToValidator[validatorId].lastChangedMonth) { initialSubtractions = new uint[]( _effectiveDelegatedToValidator[validatorId].lastChangedMonth.sub(currentMonth) ); for (uint i = 0; i < initialSubtractions.length; ++i) { initialSubtractions[i] = _effectiveDelegatedToValidator[validatorId] .subtractDiff[currentMonth.add(i).add(1)]; } } _effectiveDelegatedToValidator[validatorId].reduceSequence(coefficient, currentMonth); _putToSlashingLog(_slashesOfValidator[validatorId], coefficient, currentMonth); _slashes.push(SlashingEvent({reducingCoefficient: coefficient, validatorId: validatorId, month: currentMonth})); BountyV2 bounty = _getBounty(); bounty.handleDelegationRemoving( initialEffectiveDelegated.sub( _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(currentMonth) ), currentMonth ); for (uint i = 0; i < initialSubtractions.length; ++i) { bounty.handleDelegationAdd( initialSubtractions[i].sub( _effectiveDelegatedToValidator[validatorId].subtractDiff[currentMonth.add(i).add(1)] ), currentMonth.add(i).add(1) ); } } /** * @dev Allows Distributor contract to return and update the effective * amount delegated (minus slash) to a validator for a given month. */ function getAndUpdateEffectiveDelegatedToValidator(uint validatorId, uint month) external allowTwo("Bounty", "Distributor") returns (uint) { return _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(month); } /** * @dev Return and update the amount delegated to a validator for the * current month. */ function getAndUpdateDelegatedByHolderToValidatorNow(address holder, uint validatorId) external returns (uint) { return _getAndUpdateDelegatedByHolderToValidator(holder, validatorId, _getCurrentMonth()); } function getEffectiveDelegatedValuesByValidator(uint validatorId) external view returns (uint[] memory) { return _effectiveDelegatedToValidator[validatorId].getValuesInSequence(); } function getEffectiveDelegatedToValidator(uint validatorId, uint month) external view returns (uint) { return _effectiveDelegatedToValidator[validatorId].getValueInSequence(month); } function getDelegatedToValidator(uint validatorId, uint month) external view returns (uint) { return _delegatedToValidator[validatorId].getValue(month); } /** * @dev Return Delegation struct. */ function getDelegation(uint delegationId) external view checkDelegationExists(delegationId) returns (Delegation memory) { return delegations[delegationId]; } /** * @dev Returns the first delegation month. */ function getFirstDelegationMonth(address holder, uint validatorId) external view returns(uint) { return _firstDelegationMonth[holder].byValidator[validatorId]; } /** * @dev Returns a validator's total number of delegations. */ function getDelegationsByValidatorLength(uint validatorId) external view returns (uint) { return delegationsByValidator[validatorId].length; } /** * @dev Returns a holder's total number of delegations. */ function getDelegationsByHolderLength(address holder) external view returns (uint) { return delegationsByHolder[holder].length; } function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); } /** * @dev Process slashes up to the given limit. */ function processSlashes(address holder, uint limit) public { _sendSlashingSignals(_processSlashesWithoutSignals(holder, limit)); } /** * @dev Process all slashes. */ function processAllSlashes(address holder) public { processSlashes(holder, 0); } /** * @dev Returns the token state of a given delegation. */ function getState(uint delegationId) public view checkDelegationExists(delegationId) returns (State state) { if (delegations[delegationId].started == 0) { if (delegations[delegationId].finished == 0) { if (_getCurrentMonth() == _getTimeHelpers().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; } } } } } /** * @dev Returns the amount of tokens in PENDING delegation state. */ function getLockedInPendingDelegations(address holder) public view returns (uint) { uint currentMonth = _getCurrentMonth(); if (_lockedInPendingDelegations[holder].month < currentMonth) { return 0; } else { return _lockedInPendingDelegations[holder].amount; } } /** * @dev Checks whether there are any unprocessed slashes. */ function hasUnprocessedSlashes(address holder) public view returns (bool) { return _everDelegated(holder) && _firstUnprocessedSlashByHolder[holder] < _slashes.length; } // private /** * @dev Allows Nodes contract to get and update the amount delegated * to validator for a given month. */ function _getAndUpdateDelegatedToValidator(uint validatorId, uint month) private returns (uint) { return _delegatedToValidator[validatorId].getAndUpdateValue(month); } /** * @dev Adds a new delegation proposal. */ 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); } /** * @dev Returns the month when a delegation ends. */ 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(); assert(_lockedInPendingDelegations[holder].month == currentMonth); _lockedInPendingDelegations[holder].amount = _lockedInPendingDelegations[holder].amount.sub(amount); } function _getCurrentMonth() private view returns (uint) { return _getTimeHelpers().getCurrentMonth(); } /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ 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; } } /** * @dev Checks whether the holder has performed a delegation. */ 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); } /** * @dev Returns the delegated amount after a slashing event. */ 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.getPunisher()); 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 { 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( _getDelegationPeriodManager().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 _subtractFromAllStatistics(uint delegationId) private { 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( _getDelegationPeriodManager().stakeMultipliers(delegations[delegationId].delegationPeriod)); _removeFromEffectiveDelegatedToValidator( delegations[delegationId].validatorId, effectiveAmount, delegations[delegationId].finished); _removeFromEffectiveDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, effectiveAmount, delegations[delegationId].finished); _getTokenLaunchLocker().handleDelegationRemoving( delegations[delegationId].holder, delegationId, delegations[delegationId].finished); _getBounty().handleDelegationRemoving( effectiveAmount, delegations[delegationId].finished); } /** * @dev Checks whether delegation to a validator is allowed. * * Requirements: * * - Delegator must not have reached the validator limit. * - Delegation must be made in or after the first delegation month. */ function _checkIfDelegationIsAllowed(address holder, uint validatorId) private view returns (bool) { require( _numberOfValidatorsPerDelegator[holder].delegated[validatorId] > 0 || ( _numberOfValidatorsPerDelegator[holder].delegated[validatorId] == 0 && _numberOfValidatorsPerDelegator[holder].number < _getConstantsHolder().limitValidatorsPerDelegator() ), "Limit of validators is reached" ); } function _getDelegationPeriodManager() private view returns (DelegationPeriodManager) { return DelegationPeriodManager(contractManager.getDelegationPeriodManager()); } function _getBounty() private view returns (BountyV2) { return BountyV2(contractManager.getBounty()); } function _getValidatorService() private view returns (ValidatorService) { return ValidatorService(contractManager.getValidatorService()); } function _getTimeHelpers() private view returns (TimeHelpers) { return TimeHelpers(contractManager.getTimeHelpers()); } function _getTokenLaunchLocker() private view returns (TokenLaunchLocker) { return TokenLaunchLocker(contractManager.getTokenLaunchLocker()); } function _getConstantsHolder() private view returns (ConstantsHolder) { return ConstantsHolder(contractManager.getConstantsHolder()); } function _accept(uint delegationId) private { _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"); SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(delegations[delegationId].holder); _addToAllStatistics(delegationId); uint amount = delegations[delegationId].amount; _getTokenLaunchLocker().handleDelegationAdd( delegations[delegationId].holder, delegationId, amount, delegations[delegationId].started ); uint effectiveAmount = amount.mul( _getDelegationPeriodManager().stakeMultipliers(delegations[delegationId].delegationPeriod) ); _getBounty().handleDelegationAdd( effectiveAmount, delegations[delegationId].started ); _sendSlashingSignals(slashingSignals); emit DelegationAccepted(delegationId); } }
// 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 "./delegation/DelegationController.sol"; import "./delegation/PartialDifferences.sol"; import "./delegation/TimeHelpers.sol"; import "./delegation/ValidatorService.sol"; import "./ConstantsHolder.sol"; import "./Nodes.sol"; import "./Permissions.sol"; contract BountyV2 is Permissions { using PartialDifferences for PartialDifferences.Value; using PartialDifferences for PartialDifferences.Sequence; struct BountyHistory { uint month; uint bountyPaid; } 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 EPOCHS_PER_YEAR = 12; uint public constant SECONDS_PER_DAY = 24 * 60 * 60; uint public constant BOUNTY_WINDOW_SECONDS = 3 * SECONDS_PER_DAY; uint private _nextEpoch; uint private _epochPool; uint private _bountyWasPaidInCurrentEpoch; bool public bountyReduction; uint public nodeCreationWindowSeconds; PartialDifferences.Value private _effectiveDelegatedSum; // validatorId amount of nodes mapping (uint => uint) public nodesByValidator; // deprecated // validatorId => BountyHistory mapping (uint => BountyHistory) private _bountyHistory; function calculateBounty(uint nodeIndex) external allow("SkaleManager") returns (uint) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); Nodes nodes = Nodes(contractManager.getContract("Nodes")); TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController") ); require( _getNextRewardTimestamp(nodeIndex, nodes, timeHelpers) <= now, "Transaction is sent too early" ); uint validatorId = nodes.getValidatorId(nodeIndex); if (nodesByValidator[validatorId] > 0) { delete nodesByValidator[validatorId]; } uint currentMonth = timeHelpers.getCurrentMonth(); _refillEpochPool(currentMonth, timeHelpers, constantsHolder); _prepareBountyHistory(validatorId, currentMonth); uint bounty = _calculateMaximumBountyAmount( _epochPool, _effectiveDelegatedSum.getAndUpdateValue(currentMonth), _bountyWasPaidInCurrentEpoch, nodeIndex, _bountyHistory[validatorId].bountyPaid, delegationController.getAndUpdateEffectiveDelegatedToValidator(validatorId, currentMonth), delegationController.getAndUpdateDelegatedToValidatorNow(validatorId), constantsHolder, nodes ); _bountyHistory[validatorId].bountyPaid = _bountyHistory[validatorId].bountyPaid.add(bounty); bounty = _reduceBounty( bounty, nodeIndex, nodes, constantsHolder ); _epochPool = _epochPool.sub(bounty); _bountyWasPaidInCurrentEpoch = _bountyWasPaidInCurrentEpoch.add(bounty); return bounty; } function enableBountyReduction() external onlyOwner { bountyReduction = true; } function disableBountyReduction() external onlyOwner { bountyReduction = false; } function setNodeCreationWindowSeconds(uint window) external allow("Nodes") { nodeCreationWindowSeconds = window; } function handleDelegationAdd( uint amount, uint month ) external allow("DelegationController") { _effectiveDelegatedSum.addToValue(amount, month); } function handleDelegationRemoving( uint amount, uint month ) external allow("DelegationController") { _effectiveDelegatedSum.subtractFromValue(amount, month); } function populate() external onlyOwner { ValidatorService validatorService = ValidatorService(contractManager.getValidatorService()); DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController") ); TimeHelpers timeHelpers = TimeHelpers(contractManager.getTimeHelpers()); uint currentMonth = timeHelpers.getCurrentMonth(); // clean existing data for ( uint i = _effectiveDelegatedSum.firstUnprocessedMonth; i < _effectiveDelegatedSum.lastChangedMonth.add(1); ++i ) { delete _effectiveDelegatedSum.addDiff[i]; delete _effectiveDelegatedSum.subtractDiff[i]; } delete _effectiveDelegatedSum.value; delete _effectiveDelegatedSum.lastChangedMonth; _effectiveDelegatedSum.firstUnprocessedMonth = currentMonth; uint[] memory validators = validatorService.getTrustedValidators(); for (uint i = 0; i < validators.length; ++i) { uint validatorId = validators[i]; uint currentEffectiveDelegated = delegationController.getAndUpdateEffectiveDelegatedToValidator(validatorId, currentMonth); uint[] memory effectiveDelegated = delegationController.getEffectiveDelegatedValuesByValidator(validatorId); if (effectiveDelegated.length > 0) { assert(currentEffectiveDelegated == effectiveDelegated[0]); } uint added = 0; for (uint j = 0; j < effectiveDelegated.length; ++j) { if (effectiveDelegated[j] != added) { if (effectiveDelegated[j] > added) { _effectiveDelegatedSum.addToValue(effectiveDelegated[j].sub(added), currentMonth + j); } else { _effectiveDelegatedSum.subtractFromValue(added.sub(effectiveDelegated[j]), currentMonth + j); } added = effectiveDelegated[j]; } } delete effectiveDelegated; } } function estimateBounty(uint nodeIndex) external view returns (uint) { ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); Nodes nodes = Nodes(contractManager.getContract("Nodes")); TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers")); DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController") ); uint currentMonth = timeHelpers.getCurrentMonth(); uint validatorId = nodes.getValidatorId(nodeIndex); uint stagePoolSize; (stagePoolSize, ) = _getEpochPool(currentMonth, timeHelpers, constantsHolder); return _calculateMaximumBountyAmount( stagePoolSize, _effectiveDelegatedSum.getValue(currentMonth), _nextEpoch == currentMonth.add(1) ? _bountyWasPaidInCurrentEpoch : 0, nodeIndex, _getBountyPaid(validatorId, currentMonth), delegationController.getEffectiveDelegatedToValidator(validatorId, currentMonth), delegationController.getDelegatedToValidator(validatorId, currentMonth), constantsHolder, nodes ); } function getNextRewardTimestamp(uint nodeIndex) external view returns (uint) { return _getNextRewardTimestamp( nodeIndex, Nodes(contractManager.getContract("Nodes")), TimeHelpers(contractManager.getContract("TimeHelpers")) ); } function getEffectiveDelegatedSum() external view returns (uint[] memory) { return _effectiveDelegatedSum.getValues(); } function initialize(address contractManagerAddress) public override initializer { Permissions.initialize(contractManagerAddress); _nextEpoch = 0; _epochPool = 0; _bountyWasPaidInCurrentEpoch = 0; bountyReduction = false; nodeCreationWindowSeconds = 3 * SECONDS_PER_DAY; } // private function _calculateMaximumBountyAmount( uint epochPoolSize, uint effectiveDelegatedSum, uint bountyWasPaidInCurrentEpoch, uint nodeIndex, uint bountyPaidToTheValidator, uint effectiveDelegated, uint delegated, 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; } if (effectiveDelegatedSum == 0) { // no delegations in the system return 0; } if (constantsHolder.msr() == 0) { return 0; } uint bounty = _calculateBountyShare( epochPoolSize.add(bountyWasPaidInCurrentEpoch), effectiveDelegated, effectiveDelegatedSum, delegated.div(constantsHolder.msr()), bountyPaidToTheValidator ); return bounty; } function _calculateBountyShare( uint monthBounty, uint effectiveDelegated, uint effectiveDelegatedSum, uint maxNodesAmount, uint paidToValidator ) private pure returns (uint) { if (maxNodesAmount > 0) { uint totalBountyShare = monthBounty .mul(effectiveDelegated) .div(effectiveDelegatedSum); return _min( totalBountyShare.div(maxNodesAmount), totalBountyShare.sub(paidToValidator) ); } else { return 0; } } function _getFirstEpoch(TimeHelpers timeHelpers, ConstantsHolder constantsHolder) private view returns (uint) { return timeHelpers.timestampToMonth(constantsHolder.launchTimestamp()); } function _getEpochPool( uint currentMonth, TimeHelpers timeHelpers, ConstantsHolder constantsHolder ) private view returns (uint epochPool, uint nextEpoch) { epochPool = _epochPool; for (nextEpoch = _nextEpoch; nextEpoch <= currentMonth; ++nextEpoch) { epochPool = epochPool.add(_getEpochReward(nextEpoch, timeHelpers, constantsHolder)); } } function _refillEpochPool(uint currentMonth, TimeHelpers timeHelpers, ConstantsHolder constantsHolder) private { uint epochPool; uint nextEpoch; (epochPool, nextEpoch) = _getEpochPool(currentMonth, timeHelpers, constantsHolder); if (_nextEpoch < nextEpoch) { (_epochPool, _nextEpoch) = (epochPool, nextEpoch); _bountyWasPaidInCurrentEpoch = 0; } } function _getEpochReward( uint epoch, TimeHelpers timeHelpers, ConstantsHolder constantsHolder ) private view returns (uint) { uint firstEpoch = _getFirstEpoch(timeHelpers, constantsHolder); if (epoch < firstEpoch) { return 0; } uint epochIndex = epoch.sub(firstEpoch); uint year = epochIndex.div(EPOCHS_PER_YEAR); if (year >= 6) { uint power = year.sub(6).div(3).add(1); if (power < 256) { return YEAR6_BOUNTY.div(2 ** power).div(EPOCHS_PER_YEAR); } else { return 0; } } else { uint[6] memory customBounties = [ YEAR1_BOUNTY, YEAR2_BOUNTY, YEAR3_BOUNTY, YEAR4_BOUNTY, YEAR5_BOUNTY, YEAR6_BOUNTY ]; return customBounties[year].div(EPOCHS_PER_YEAR); } } function _reduceBounty( uint bounty, uint nodeIndex, Nodes nodes, ConstantsHolder constants ) private returns (uint reducedBounty) { if (!bountyReduction) { return bounty; } reducedBounty = bounty; if (!nodes.checkPossibilityToMaintainNode(nodes.getValidatorId(nodeIndex), nodeIndex)) { reducedBounty = reducedBounty.div(constants.MSR_REDUCING_COEFFICIENT()); } } function _prepareBountyHistory(uint validatorId, uint currentMonth) private { if (_bountyHistory[validatorId].month < currentMonth) { _bountyHistory[validatorId].month = currentMonth; delete _bountyHistory[validatorId].bountyPaid; } } function _getBountyPaid(uint validatorId, uint month) private view returns (uint) { require(_bountyHistory[validatorId].month <= month, "Can't get bounty paid"); if (_bountyHistory[validatorId].month == month) { return _bountyHistory[validatorId].bountyPaid; } else { return 0; } } function _getNextRewardTimestamp(uint nodeIndex, Nodes nodes, TimeHelpers timeHelpers) private view returns (uint) { uint lastRewardTimestamp = nodes.getNodeLastRewardDate(nodeIndex); uint lastRewardMonth = timeHelpers.timestampToMonth(lastRewardTimestamp); uint lastRewardMonthStart = timeHelpers.monthToTimestamp(lastRewardMonth); uint timePassedAfterMonthStart = lastRewardTimestamp.sub(lastRewardMonthStart); uint currentMonth = timeHelpers.getCurrentMonth(); assert(lastRewardMonth <= currentMonth); if (lastRewardMonth == currentMonth) { uint nextMonthStart = timeHelpers.monthToTimestamp(currentMonth.add(1)); uint nextMonthFinish = timeHelpers.monthToTimestamp(lastRewardMonth.add(2)); if (lastRewardTimestamp < lastRewardMonthStart.add(nodeCreationWindowSeconds)) { return nextMonthStart.sub(BOUNTY_WINDOW_SECONDS); } else { return _min(nextMonthStart.add(timePassedAfterMonthStart), nextMonthFinish.sub(BOUNTY_WINDOW_SECONDS)); } } else if (lastRewardMonth.add(1) == currentMonth) { uint currentMonthStart = timeHelpers.monthToTimestamp(currentMonth); uint currentMonthFinish = timeHelpers.monthToTimestamp(currentMonth.add(1)); return _min( currentMonthStart.add(_max(timePassedAfterMonthStart, nodeCreationWindowSeconds)), currentMonthFinish.sub(BOUNTY_WINDOW_SECONDS) ); } else { uint currentMonthStart = timeHelpers.monthToTimestamp(currentMonth); return currentMonthStart.add(nodeCreationWindowSeconds); } } function _min(uint a, uint b) private pure returns (uint) { if (a < b) { return a; } else { return b; } } function _max(uint a, uint b) private pure returns (uint) { if (a < b) { return b; } else { return a; } } }
// 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 ConstantsHolder * @dev Contract contains constants and common variables for the SKALE Network. */ 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/32 of Node) uint8 public constant MEDIUM_DIVISOR = 32; // 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; uint public complaintTimelimit; /** * @dev Allows the Owner to set new reward and delta periods * This function is only for tests. */ function setPeriods(uint32 newRewardPeriod, uint32 newDeltaPeriod) external onlyOwner { require( newRewardPeriod >= newDeltaPeriod && newRewardPeriod - newDeltaPeriod >= checkTime, "Incorrect Periods" ); rewardPeriod = newRewardPeriod; deltaPeriod = newDeltaPeriod; } /** * @dev Allows the Owner to set the new check time. * This function is only for tests. */ function setCheckTime(uint newCheckTime) external onlyOwner { require(rewardPeriod - deltaPeriod >= checkTime, "Incorrect check time"); checkTime = newCheckTime; } /** * @dev Allows the Owner to set the allowable latency in milliseconds. * This function is only for testing purposes. */ function setLatency(uint32 newAllowableLatency) external onlyOwner { allowableLatency = newAllowableLatency; } /** * @dev Allows the Owner to set the minimum stake requirement. */ function setMSR(uint newMSR) external onlyOwner { msr = newMSR; } /** * @dev Allows the Owner to set the launch timestamp. */ function setLaunchTimestamp(uint timestamp) external onlyOwner { require(now < launchTimestamp, "Cannot set network launch timestamp because network is already launched"); launchTimestamp = timestamp; } /** * @dev Allows the Owner to set the node rotation delay. */ function setRotationDelay(uint newDelay) external onlyOwner { rotationDelay = newDelay; } /** * @dev Allows the Owner to set the proof-of-use lockup period. */ function setProofOfUseLockUpPeriod(uint periodDays) external onlyOwner { proofOfUseLockUpPeriodDays = periodDays; } /** * @dev Allows the Owner to set the proof-of-use delegation percentage * requirement. */ function setProofOfUseDelegationPercentage(uint percentage) external onlyOwner { require(percentage <= 100, "Percentage value is incorrect"); proofOfUseDelegationPercentage = percentage; } /** * @dev Allows the Owner to set the maximum number of validators that a * single delegator can delegate to. */ function setLimitValidatorsPerDelegator(uint newLimit) external onlyOwner { limitValidatorsPerDelegator = newLimit; } function setSchainCreationTimeStamp(uint timestamp) external onlyOwner { schainCreationTimeStamp = timestamp; } function setMinimalSchainLifetime(uint lifetime) external onlyOwner { minimalSchainLifetime = lifetime; } function setComplaintTimelimit(uint timelimit) external onlyOwner { complaintTimelimit = timelimit; } 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; complaintTimelimit = 1800; } }
// 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 "@openzeppelin/contracts-ethereum-package/contracts/access/Ownable.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/utils/Address.sol"; import "./utils/StringUtils.sol"; /** * @title ContractManager * @dev Contract contains the actual current mapping from contract IDs * (in the form of human-readable strings) to addresses. */ contract ContractManager is OwnableUpgradeSafe { using StringUtils for string; using Address for address; string public constant BOUNTY = "Bounty"; string public constant CONSTANTS_HOLDER = "ConstantsHolder"; string public constant DELEGATION_PERIOD_MANAGER = "DelegationPeriodManager"; string public constant PUNISHER = "Punisher"; string public constant SKALE_TOKEN = "SkaleToken"; string public constant TIME_HELPERS = "TimeHelpers"; string public constant TOKEN_LAUNCH_LOCKER = "TokenLaunchLocker"; string public constant TOKEN_STATE = "TokenState"; string public constant VALIDATOR_SERVICE = "ValidatorService"; // mapping of actual smart contracts addresses mapping (bytes32 => address) public contracts; /** * @dev Emitted when contract is upgraded. */ event ContractUpgraded(string contractsName, address contractsAddress); function initialize() external initializer { OwnableUpgradeSafe.__Ownable_init(); } /** * @dev Allows the Owner to add contract to mapping of contract addresses. * * Emits a {ContractUpgraded} event. * * Requirements: * * - New address is non-zero. * - Contract is not already added. * - Contract address contains code. */ 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 contract address does not contain code"); // add newContractsAddress to mapping of actual contract addresses contracts[contractId] = newContractsAddress; emit ContractUpgraded(contractsName, newContractsAddress); } /** * @dev Returns contract address. * * Requirements: * * - Contract must exist. */ function getDelegationPeriodManager() external view returns (address) { return getContract(DELEGATION_PERIOD_MANAGER); } function getBounty() external view returns (address) { return getContract(BOUNTY); } function getValidatorService() external view returns (address) { return getContract(VALIDATOR_SERVICE); } function getTimeHelpers() external view returns (address) { return getContract(TIME_HELPERS); } function getTokenLaunchLocker() external view returns (address) { return getContract(TOKEN_LAUNCH_LOCKER); } function getConstantsHolder() external view returns (address) { return getContract(CONSTANTS_HOLDER); } function getSkaleToken() external view returns (address) { return getContract(SKALE_TOKEN); } function getTokenState() external view returns (address) { return getContract(TOKEN_STATE); } function getPunisher() external view returns (address) { return getContract(PUNISHER); } function getContract(string memory name) public 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 /* Nodes.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin @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 "@openzeppelin/contracts-ethereum-package/contracts/utils/SafeCast.sol"; import "./delegation/DelegationController.sol"; import "./delegation/ValidatorService.sol"; import "./BountyV2.sol"; import "./ConstantsHolder.sol"; import "./Permissions.sol"; /** * @title Nodes * @dev This contract contains all logic to manage SKALE Network nodes states, * space availability, stake requirement checks, and exit functions. * * Nodes may be in one of several states: * * - Active: Node is registered and is in network operation. * - Leaving: Node has begun exiting from the network. * - Left: Node has left the network. * - In_Maintenance: Node is temporarily offline or undergoing infrastructure * maintenance * * Note: Online nodes contain both Active and Leaving states. */ 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; string domainName; } // 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; string domainName; } // 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; /** * @dev Emitted when a node is created. */ event NodeCreated( uint nodeIndex, address owner, string name, bytes4 ip, bytes4 publicIP, uint16 port, uint16 nonce, string domainName, uint time, uint gasSpend ); /** * @dev Emitted when a node completes a network exit. */ event ExitCompleted( uint nodeIndex, uint time, uint gasSpend ); /** * @dev Emitted when a node begins to exit from the network. */ event ExitInitialized( uint nodeIndex, uint startLeavingPeriod, uint time, uint gasSpend ); modifier checkNodeExists(uint nodeIndex) { require(nodeIndex < nodes.length, "Node with such index does not exist"); _; } modifier onlyNodeOrAdmin(uint nodeIndex) { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); require( isNodeExist(msg.sender, nodeIndex) || _isAdmin(msg.sender) || getValidatorId(nodeIndex) == validatorService.getValidatorId(msg.sender), "Sender is not permitted to call this function" ); _; } /** * @dev Allows Schains and SchainsInternal contracts to occupy available * space on a node. * * Returns whether operation is successful. */ 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 Allows Schains contract to occupy free space on a node. * * Returns whether operation is successful. */ function addSpaceToNode(uint nodeIndex, uint8 space) external checkNodeExists(nodeIndex) allow("Schains") { if (space > 0) { _moveNodeToNewSpaceMap( nodeIndex, uint(spaceOfNodes[nodeIndex].freeSpace).add(space).toUint8() ); } } /** * @dev Allows SkaleManager to change a node's last reward date. */ function changeNodeLastRewardDate(uint nodeIndex) external checkNodeExists(nodeIndex) allow("SkaleManager") { nodes[nodeIndex].lastRewardDate = block.timestamp; } /** * @dev Allows SkaleManager to change a node's finish time. */ function changeNodeFinishTime(uint nodeIndex, uint time) external checkNodeExists(nodeIndex) allow("SkaleManager") { nodes[nodeIndex].finishTime = time; } /** * @dev Allows SkaleManager contract to create new node and add it to the * Nodes contract. * * Emits a {NodeCreated} event. * * Requirements: * * - Node IP must be non-zero. * - Node IP must be available. * - Node name must not already be registered. * - Node port must be greater than zero. */ 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 is already registered"); require(params.port > 0, "Port is zero"); require(from == _publicKeyToAddress(params.publicKey), "Public Key is incorrect"); 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, params.domainName, validatorId); emit NodeCreated( nodeIndex, from, params.name, params.ip, params.publicIp, params.port, params.nonce, params.domainName, block.timestamp, gasleft()); } /** * @dev Allows SkaleManager contract to initiate a node exit procedure. * * Returns whether the operation is successful. * * Emits an {ExitInitialized} event. */ function initExit(uint nodeIndex) external checkNodeExists(nodeIndex) allow("SkaleManager") returns (bool) { require(isNodeActive(nodeIndex), "Node should be Active"); _setNodeLeaving(nodeIndex); emit ExitInitialized( nodeIndex, block.timestamp, block.timestamp, gasleft()); return true; } /** * @dev Allows SkaleManager contract to complete a node exit procedure. * * Returns whether the operation is successful. * * Emits an {ExitCompleted} event. * * Requirements: * * - Node must have already initialized a node exit procedure. */ 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; } /** * @dev Allows SkaleManager contract to delete a validator's node. * * Requirements: * * - Validator ID must exist. */ function deleteNodeForValidator(uint validatorId, uint nodeIndex) external checkNodeExists(nodeIndex) allow("SkaleManager") { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); require(validatorService.validatorExists(validatorId), "Validator 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(); address nodeOwner = _publicKeyToAddress(nodes[nodeIndex].publicKey); if (validatorService.getValidatorIdByNodeAddress(nodeOwner) == validatorId) { if (nodeIndexes[nodeOwner].numberOfNodes == 1 && !validatorService.validatorAddressExists(nodeOwner)) { validatorService.removeNodeAddress(validatorId, nodeOwner); } nodeIndexes[nodeOwner].isNodeExist[nodeIndex] = false; nodeIndexes[nodeOwner].numberOfNodes--; } } /** * @dev Allows SkaleManager contract to check whether a validator has * sufficient stake to create another node. * * Requirements: * * - Validator must be included on trusted list if trusted list is enabled. * - Validator must have sufficient stake to operate an additional node. */ 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"); } /** * @dev Allows SkaleManager contract to check whether a validator has * sufficient stake to maintain a node. * * Returns whether validator can maintain node with current stake. * * Requirements: * * - Validator ID and nodeIndex must both exist. */ 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 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; } /** * @dev Allows Node to set In_Maintenance status. * * Requirements: * * - Node must already be Active. * - `msg.sender` must be owner of Node, validator, or SkaleManager. */ function setNodeInMaintenance(uint nodeIndex) external onlyNodeOrAdmin(nodeIndex) { require(nodes[nodeIndex].status == NodeStatus.Active, "Node is not Active"); _setNodeInMaintenance(nodeIndex); } /** * @dev Allows Node to remove In_Maintenance status. * * Requirements: * * - Node must already be In Maintenance. * - `msg.sender` must be owner of Node, validator, or SkaleManager. */ function removeNodeFromInMaintenance(uint nodeIndex) external onlyNodeOrAdmin(nodeIndex) { require(nodes[nodeIndex].status == NodeStatus.In_Maintenance, "Node is not In Maintenance"); _setNodeActive(nodeIndex); } function setDomainName(uint nodeIndex, string memory domainName) external onlyNodeOrAdmin(nodeIndex) { nodes[nodeIndex].domainName = domainName; } /** * @dev Returns nodes with space availability. */ 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 Checks whether it is time for a node's reward. */ function isTimeForReward(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (bool) { return BountyV2(contractManager.getBounty()).getNextRewardTimestamp(nodeIndex) <= now; } /** * @dev Returns IP address of a given node. * * Requirements: * * - Node must exist. */ function getNodeIP(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (bytes4) { require(nodeIndex < nodes.length, "Node does not exist"); return nodes[nodeIndex].ip; } /** * @dev Returns domain name of a given node. * * Requirements: * * - Node must exist. */ function getNodeDomainName(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (string memory) { return nodes[nodeIndex].domainName; } /** * @dev Returns the port of a given node. * * Requirements: * * - Node must exist. */ function getNodePort(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (uint16) { return nodes[nodeIndex].port; } /** * @dev Returns the public key of a given node. */ function getNodePublicKey(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (bytes32[2] memory) { return nodes[nodeIndex].publicKey; } /** * @dev Returns an address of a given node. */ function getNodeAddress(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (address) { return _publicKeyToAddress(nodes[nodeIndex].publicKey); } /** * @dev Returns the finish exit time of a given node. */ function getNodeFinishTime(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (uint) { return nodes[nodeIndex].finishTime; } /** * @dev Checks whether a node has left the network. */ 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 Returns a given node's last reward date. */ function getNodeLastRewardDate(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (uint) { return nodes[nodeIndex].lastRewardDate; } /** * @dev Returns a given node's next reward date. */ function getNodeNextRewardDate(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (uint) { return BountyV2(contractManager.getBounty()).getNextRewardTimestamp(nodeIndex); } /** * @dev Returns the total number of registered nodes. */ function getNumberOfNodes() external view returns (uint) { return nodes.length; } /** * @dev Returns the total number of online nodes. * * Note: Online nodes are equal to the number of active plus leaving nodes. */ function getNumberOnlineNodes() external view returns (uint) { return numberOfActiveNodes.add(numberOfLeavingNodes); } /** * @dev Returns 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 Returns active nodes linked to the `msg.sender` (validator address). */ 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 (isNodeExist(msg.sender, indexOfNodes) && isNodeActive(indexOfNodes)) { activeNodesByAddress[indexOfActiveNodesByAddress] = indexOfNodes; indexOfActiveNodesByAddress++; } } } /** * @dev Return active node IDs. */ 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++; } } } /** * @dev Return a given node's current status. */ function getNodeStatus(uint nodeIndex) external view checkNodeExists(nodeIndex) returns (NodeStatus) { return nodes[nodeIndex].status; } /** * @dev Return a validator's linked nodes. * * Requirements: * * - Validator ID must exist. */ function getValidatorNodeIndexes(uint validatorId) external view returns (uint[] memory) { ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService")); require(validatorService.validatorExists(validatorId), "Validator ID does not exist"); return validatorToNodeIndexes[validatorId]; } /** * @dev constructor in Permissions approach. */ function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); numberOfActiveNodes = 0; numberOfLeavingNodes = 0; numberOfLeftNodes = 0; } /** * @dev Returns the Validator ID for a given node. */ function getValidatorId(uint nodeIndex) public view checkNodeExists(nodeIndex) returns (uint) { return nodes[nodeIndex].validatorId; } /** * @dev Checks whether a node exists for a given address. */ function isNodeExist(address from, uint nodeIndex) public view checkNodeExists(nodeIndex) returns (bool) { return nodeIndexes[from].isNodeExist[nodeIndex]; } /** * @dev Checks whether a node's status is Active. */ function isNodeActive(uint nodeIndex) public view checkNodeExists(nodeIndex) returns (bool) { return nodes[nodeIndex].status == NodeStatus.Active; } /** * @dev Checks whether a node's status is Leaving. */ function isNodeLeaving(uint nodeIndex) public view checkNodeExists(nodeIndex) returns (bool) { return nodes[nodeIndex].status == NodeStatus.Leaving; } /** * @dev Returns number of nodes with available space. */ 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); } } /** * @dev Returns the index of a given node within the validator's node index. */ 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; } /** * @dev Moves a node to a new space mapping. */ 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 Changes a node's status to Active. */ function _setNodeActive(uint nodeIndex) private { nodes[nodeIndex].status = NodeStatus.Active; numberOfActiveNodes = numberOfActiveNodes.add(1); } /** * @dev Changes a node's status to In_Maintenance. */ function _setNodeInMaintenance(uint nodeIndex) private { nodes[nodeIndex].status = NodeStatus.In_Maintenance; numberOfActiveNodes = numberOfActiveNodes.sub(1); } /** * @dev Changes a node's status to Left. */ 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 Changes a node's status to Leaving. */ function _setNodeLeaving(uint nodeIndex) private { nodes[nodeIndex].status = NodeStatus.Leaving; numberOfActiveNodes--; numberOfLeavingNodes++; } /** * @dev Adds node to array. */ function _addNode( address from, string memory name, bytes4 ip, bytes4 publicIP, uint16 port, bytes32[2] memory publicKey, string memory domainName, 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, domainName: domainName })); 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++; } /** * @dev Deletes node from array. */ 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; } function _publicKeyToAddress(bytes32[2] memory pubKey) private pure returns (address) { bytes32 hash = keccak256(abi.encodePacked(pubKey[0], pubKey[1])); bytes20 addr; for (uint8 i = 12; i < 32; i++) { addr |= bytes20(hash[i] & 0xFF) >> ((i - 12) * 8); } return address(addr); } function _min(uint a, uint b) private pure returns (uint) { if (a < b) { return a; } else { return b; } } }
// 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 "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/access/AccessControl.sol"; import "./ContractManager.sol"; /** * @title Permissions * @dev Contract is connected module for Upgradeable approach, knows ContractManager */ contract Permissions is AccessControlUpgradeSafe { using SafeMath for uint; using Address for address; ContractManager public contractManager; /** * @dev Modifier to make a function callable only when caller is the Owner. * * Requirements: * * - The caller must be the owner. */ modifier onlyOwner() { require(_isOwner(), "Caller is not the owner"); _; } /** * @dev Modifier to make a function callable only when caller is an Admin. * * Requirements: * * - The caller must be an admin. */ modifier onlyAdmin() { require(_isAdmin(msg.sender), "Caller is not an admin"); _; } /** * @dev Modifier to make a function callable only when caller is the Owner * or `contractName` contract. * * Requirements: * * - The caller must be the owner or `contractName`. */ modifier allow(string memory contractName) { require( contractManager.getContract(contractName) == msg.sender || _isOwner(), "Message sender is invalid"); _; } /** * @dev Modifier to make a function callable only when caller is the Owner * or `contractName1` or `contractName2` contract. * * Requirements: * * - The caller must be the owner, `contractName1`, or `contractName2`. */ modifier allowTwo(string memory contractName1, string memory contractName2) { require( contractManager.getContract(contractName1) == msg.sender || contractManager.getContract(contractName2) == msg.sender || _isOwner(), "Message sender is invalid"); _; } /** * @dev Modifier to make a function callable only when caller is the Owner * or `contractName1`, `contractName2`, or `contractName3` contract. * * Requirements: * * - The caller must be the owner, `contractName1`, `contractName2`, or * `contractName3`. */ modifier allowThree(string memory contractName1, string memory contractName2, string memory contractName3) { require( contractManager.getContract(contractName1) == msg.sender || contractManager.getContract(contractName2) == msg.sender || contractManager.getContract(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 /* 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 { mapping (uint => uint) public stakeMultipliers; /** * @dev Emitted when a new delegation period is specified. */ event DelegationPeriodWasSet( uint length, uint stakeMultiplier ); /** * @dev Allows the Owner to create a new available delegation period and * stake multiplier in the network. * * Emits a {DelegationPeriodWasSet} event. */ function setDelegationPeriod(uint monthsCount, uint stakeMultiplier) external onlyOwner { require(stakeMultipliers[monthsCount] == 0, "Delegation perios is already set"); stakeMultipliers[monthsCount] = stakeMultiplier; emit DelegationPeriodWasSet(monthsCount, stakeMultiplier); } /** * @dev Checks whether given delegation period is allowed. */ function isDelegationPeriodAllowed(uint monthsCount) external view returns (bool) { return stakeMultipliers[monthsCount] != 0; } /** * @dev Initial delegation period and multiplier settings. */ function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); stakeMultipliers[2] = 100; // 2 months at 100 // stakeMultipliers[6] = 150; // 6 months at 150 // stakeMultipliers[12] = 200; // 12 months at 200 } }
// 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 "../utils/MathUtils.sol"; import "../utils/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 getValueInSequence(Sequence storage sequence, uint month) internal view returns (uint) { if (sequence.firstUnprocessedMonth == 0) { return 0; } if (sequence.firstUnprocessedMonth <= month) { uint value = sequence.value[sequence.firstUnprocessedMonth.sub(1)]; for (uint i = sequence.firstUnprocessedMonth; i <= month; ++i) { value = value.add(sequence.addDiff[i]).sub(sequence.subtractDiff[i]); } return value; } else { return sequence.value[month]; } } function getValuesInSequence(Sequence storage sequence) internal view returns (uint[] memory values) { if (sequence.firstUnprocessedMonth == 0) { return values; } uint begin = sequence.firstUnprocessedMonth.sub(1); uint end = sequence.lastChangedMonth.add(1); if (end <= begin) { end = begin.add(1); } values = new uint[](end.sub(begin)); values[0] = sequence.value[sequence.firstUnprocessedMonth.sub(1)]; for (uint i = 0; i.add(1) < values.length; ++i) { uint month = sequence.firstUnprocessedMonth.add(i); values[i.add(1)] = values[i].add(sequence.addDiff[month]).sub(sequence.subtractDiff[month]); } } function reduceSequence( Sequence storage sequence, FractionUtils.Fraction memory reducingCoefficient, uint month) internal { require(month.add(1) >= sequence.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 = 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) { uint value = sequence.value; for (uint i = sequence.firstUnprocessedMonth; i <= month; ++i) { value = value.add(sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]); if (sequence.addDiff[i] > 0) { delete sequence.addDiff[i]; } if (sequence.subtractDiff[i] > 0) { delete sequence.subtractDiff[i]; } } if (sequence.value != value) { sequence.value = value; } sequence.firstUnprocessedMonth = month.add(1); } return sequence.value; } function getValue(Value storage sequence, uint month) internal view returns (uint) { require( month.add(1) >= sequence.firstUnprocessedMonth, "Cannot calculate value in the past"); if (sequence.firstUnprocessedMonth == 0) { return 0; } if (sequence.firstUnprocessedMonth <= month) { uint value = sequence.value; for (uint i = sequence.firstUnprocessedMonth; i <= month; ++i) { value = value.add(sequence.addDiff[i]).sub(sequence.subtractDiff[i]); } return value; } else { return sequence.value; } } function getValues(Value storage sequence) internal view returns (uint[] memory values) { if (sequence.firstUnprocessedMonth == 0) { return values; } uint begin = sequence.firstUnprocessedMonth.sub(1); uint end = sequence.lastChangedMonth.add(1); if (end <= begin) { end = begin.add(1); } values = new uint[](end.sub(begin)); values[0] = sequence.value; for (uint i = 0; i.add(1) < values.length; ++i) { uint month = sequence.firstUnprocessedMonth.add(i); values[i.add(1)] = values[i].add(sequence.addDiff[month]).sub(sequence.subtractDiff[month]); } } 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 /* 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 "../interfaces/delegation/ILocker.sol"; import "./ValidatorService.sol"; import "./DelegationController.sol"; /** * @title Punisher * @dev This contract handles all slashing and forgiving operations. */ contract Punisher is Permissions, ILocker { // holder => tokens mapping (address => uint) private _locked; /** * @dev Emitted upon slashing condition. */ event Slash( uint validatorId, uint amount ); /** * @dev Emitted upon forgive condition. */ event Forgive( address wallet, uint amount ); /** * @dev Allows SkaleDKG contract to execute slashing on a validator and * validator's delegations by an `amount` of tokens. * * Emits a {Slash} event. * * Requirements: * * - Validator must exist. */ 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 Admin to forgive a slashing condition. * * Emits a {Forgive} event. * * Requirements: * * - All slashes must have been processed. */ 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); } /** * @dev Allows DelegationController contract to execute slashing of * delegations. */ 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 /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ function _getAndUpdateLockedAmount(address wallet) private returns (uint) { DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController")); delegationController.processAllSlashes(wallet); return _locked[wallet]; } }
// 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 "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol"; import "../thirdparty/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 "../interfaces/delegation/ILocker.sol"; import "../ConstantsHolder.sol"; import "../utils/MathUtils.sol"; import "./DelegationController.sol"; import "./TimeHelpers.sol"; import "./PartialDifferences.sol"; /** * @title TokenLaunchLocker * @dev This contract manages lockers applied to the launch process. */ 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; /** * @dev Allows TokenLaunchManager contract to lock an amount of tokens in a * holder wallet. * * Emits a {Locked} event. */ function lock(address holder, uint amount) external allow("TokenLaunchManager") { _locked[holder] = _locked[holder].add(amount); emit Locked(holder, amount); } /** * @dev Allows DelegationController contract to notify TokenLaunchLocker * about new delegations. */ 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; } } } /** * @dev Allows DelegationController contract to notify TokenLaunchLocker * about new undelegation requests. */ 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]; } } /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ 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 (_totalDelegatedSatisfiesProofOfUseCondition(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; } } /** * @dev See {ILocker-getAndUpdateForbiddenForDelegationAmount}. */ function getAndUpdateForbiddenForDelegationAmount(address) external override returns (uint) { return 0; } function initialize(address contractManagerAddress) public override initializer { Permissions.initialize(contractManagerAddress); } // private /** * @dev Returns and updates the current delegated amount. */ function _getAndUpdateDelegatedAmount(address holder, uint currentMonth) private returns (uint) { return _delegatedAmount[holder].getAndUpdateValue(currentMonth); } /** * @dev Adds a delegated amount to the given month. */ function _addToDelegatedAmount(address holder, uint amount, uint month) private { _delegatedAmount[holder].addToValue(amount, month); } /** * @dev Removes a delegated amount from the given month. */ function _removeFromDelegatedAmount(address holder, uint amount, uint month) private { _delegatedAmount[holder].subtractFromValue(amount, month); } /** * @dev Adds the amount to the total delegated for the given month. */ function _addToTotalDelegatedAmount(address holder, uint amount, uint month) private { require( _totalDelegatedAmount[holder].month == 0 || _totalDelegatedAmount[holder].month <= month, "Cannot add to total delegated in the past"); // do not update counter if it is big enough // because it will override month value if (!_totalDelegatedSatisfiesProofOfUseCondition(holder)) { _totalDelegatedAmount[holder].delegated = _totalDelegatedAmount[holder].delegated.add(amount); _totalDelegatedAmount[holder].month = month; } } /** * @dev Unlocks tokens. * * Emits an {Unlocked} event. */ function _unlock(address holder) private { emit Unlocked(holder, _locked[holder]); delete _locked[holder]; _deleteDelegatedAmount(holder); _deleteTotalDelegatedAmount(holder); } /** * @dev Deletes the delegated amount. */ function _deleteDelegatedAmount(address holder) private { _delegatedAmount[holder].clear(); } /** * @dev Deletes the total delegated amount. */ function _deleteTotalDelegatedAmount(address holder) private { delete _totalDelegatedAmount[holder].delegated; delete _totalDelegatedAmount[holder].month; } /** * @dev Checks whether total delegated satisfies Proof-of-Use. */ function _totalDelegatedSatisfiesProofOfUseCondition(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 "../interfaces/delegation/ILocker.sol"; /** * @title Token State * @dev This contract manages lockers to control token transferability. * * The SKALE Network has three types of locked tokens: * * - Tokens that are transferrable but are currently locked into delegation with * a validator. * * - 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. * * - Tokens that are neither transferable nor delegatable * `getAndUpdateForbiddenForDelegationAmount`. This lock enforces slashing. */ contract TokenState is Permissions, ILocker { string[] private _lockers; /** * @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 ); /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ 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 See {ILocker-getAndUpdateForbiddenForDelegationAmount}. */ 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. */ 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. */ 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 "@openzeppelin/contracts-ethereum-package/contracts/cryptography/ECDSA.sol"; import "../Permissions.sol"; import "../ConstantsHolder.sol"; import "./DelegationController.sol"; import "./TimeHelpers.sol"; /** * @title ValidatorService * @dev This contract handles all validator operations including registration, * node management, validator-specific delegation parameters, and more. * * TIP: For more information see our main instructions * https://forum.skale.network/t/skale-mainnet-launch-faq/182[SKALE MainNet Launch FAQ]. * * 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 ); /** * @dev Emitted when a validator is enabled. */ event ValidatorWasEnabled( uint validatorId ); /** * @dev Emitted when a validator is disabled. */ 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 that includes a validator name, description, * commission or fee rate, and a minimum delegation amount accepted by the validator. * * Emits a {ValidatorRegistered} event. * * Requirements: * * - Sender must not already have registered a validator ID. * - Fee rate must be between 0 - 1000‰. Note: in per mille. */ 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); } /** * @dev Allows Admin to enable a validator by adding their ID to the * trusted list. * * Emits a {ValidatorWasEnabled} event. * * Requirements: * * - Validator must not already be enabled. */ function enableValidator(uint validatorId) external checkValidatorExists(validatorId) onlyAdmin { require(!_trustedValidators[validatorId], "Validator is already enabled"); _trustedValidators[validatorId] = true; trustedValidatorsList.push(validatorId); emit ValidatorWasEnabled(validatorId); } /** * @dev Allows Admin to disable a validator by removing their ID from * the trusted list. * * Emits a {ValidatorWasDisabled} event. * * Requirements: * * - Validator must not already be disabled. */ 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 trusted validator list. Once turned off, the * trusted list cannot be re-enabled. */ function disableWhitelist() external onlyOwner { useWhitelist = false; } /** * @dev Allows `msg.sender` to request a new address. * * Requirements: * * - `msg.sender` must already be a validator. * - New address must not be null. * - New address must not be already registered as a validator. */ 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; } /** * @dev Allows msg.sender to confirm an address change. * * Emits a {ValidatorAddressChanged} event. * * Requirements: * * - Must be owner of new address. */ 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 node address to validator ID. Validator must present * the node signature of the validator ID. * * Requirements: * * - Signature must be valid. * - Address must not be assigned to a validator. */ 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 node address from a validator. * * Emits a {NodeAddressWasRemoved} event. */ function unlinkNodeAddress(address nodeAddress) external { // check Validator Exist inside getValidatorId uint validatorId = getValidatorId(msg.sender); this.removeNodeAddress(validatorId, nodeAddress); emit NodeAddressWasRemoved(validatorId, nodeAddress); } /** * @dev Allows a validator to set a minimum delegation amount. */ 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. */ 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. */ 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: * * - 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: * * - 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; } function removeNodeAddress(uint validatorId, address nodeAddress) external allowTwo("ValidatorService", "Nodes") { 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; } } } /** * @dev Returns the amount of validator bond (self-delegation). */ function getAndUpdateBondAmount(uint validatorId) external returns (uint) { DelegationController delegationController = DelegationController( contractManager.getContract("DelegationController") ); return delegationController.getAndUpdateDelegatedByHolderToValidatorNow( getValidator(validatorId).validatorAddress, validatorId ); } /** * @dev Returns node addresses linked to the msg.sender. */ function getMyNodesAddresses() external view returns (address[] memory) { return getNodeAddresses(getValidatorId(msg.sender)); } /** * @dev Returns the list of trusted validators. */ function getTrustedValidators() external view returns (uint[] memory) { return trustedValidatorsList; } /** * @dev Checks whether the validator ID is linked to the validator address. */ function checkValidatorAddressToId(address validatorAddress, uint validatorId) external view returns (bool) { return getValidatorId(validatorAddress) == validatorId ? true : false; } /** * @dev Returns the validator ID linked to a node address. * * Requirements: * * - Node address must be linked to a validator. */ function getValidatorIdByNodeAddress(address nodeAddress) external view returns (uint validatorId) { validatorId = _nodeAddressToValidatorId[nodeAddress]; require(validatorId != 0, "Node address is not assigned to a validator"); } function checkValidatorCanReceiveDelegation(uint validatorId, uint amount) external view { require(isAuthorizedValidator(validatorId), "Validator is not authorized to accept delegation request"); require(isAcceptingNewRequests(validatorId), "The validator is not currently accepting new requests"); require( validators[validatorId].minimumDelegationAmount <= amount, "Amount does not meet the validator's minimum delegation amount" ); } function initialize(address contractManagerAddress) public override initializer { Permissions.initialize(contractManagerAddress); useWhitelist = true; } /** * @dev Returns a validator's node addresses. */ function getNodeAddresses(uint validatorId) public view returns (address[] memory) { return _nodeAddresses[validatorId]; } /** * @dev Checks whether validator ID exists. */ function validatorExists(uint validatorId) public view returns (bool) { return validatorId <= numberOfValidators && validatorId != 0; } /** * @dev Checks whether validator address exists. */ function validatorAddressExists(address validatorAddress) public view returns (bool) { return _validatorAddressToId[validatorAddress] != 0; } /** * @dev Checks whether validator address exists. */ function checkIfValidatorAddressExists(address validatorAddress) public view { require(validatorAddressExists(validatorAddress), "Validator address does not exist"); } /** * @dev Returns the Validator struct. */ function getValidator(uint validatorId) public view checkValidatorExists(validatorId) returns (Validator memory) { return validators[validatorId]; } /** * @dev Returns the validator ID for the given validator address. */ function getValidatorId(address validatorAddress) public view returns (uint) { checkIfValidatorAddressExists(validatorAddress); return _validatorAddressToId[validatorAddress]; } /** * @dev Checks whether the validator is currently accepting new delegation requests. */ function isAcceptingNewRequests(uint validatorId) public view checkValidatorExists(validatorId) returns (bool) { return validators[validatorId].acceptNewRequests; } function isAuthorizedValidator(uint validatorId) public view checkValidatorExists(validatorId) returns (bool) { return _trustedValidators[validatorId] || !useWhitelist; } // private /** * @dev Links a validator address to a validator ID. * * Requirements: * * - Address is not already in use by another validator. */ 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; } /** * @dev Links a node address to a validator ID. * * Requirements: * * - Node address must not be already linked to a validator. */ 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 _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; } }
// 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 the Locker functions. */ interface ILocker { /** * @dev Returns and updates the total amount of locked tokens of a given * `holder`. */ function getAndUpdateLockedAmount(address wallet) external returns (uint); /** * @dev Returns and updates the total non-transferrable and un-delegatable * amount of a given `holder`. */ function getAndUpdateForbiddenForDelegationAmount(address wallet) external returns (uint); }
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 /* 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 "@openzeppelin/contracts-ethereum-package/contracts/math/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); } // numerator - is limited by 7*10^27, we could multiply it numerator * numerator - it would less than 2^256-1 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); } }
// 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 { uint constant private _EPS = 1e6; event UnderflowError( uint a, uint b ); 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 /* 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 "@openzeppelin/contracts-ethereum-package/contracts/math/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); } }
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; }
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; }
pragma solidity ^0.6.0; import "../utils/EnumerableSet.sol"; import "../utils/Address.sol"; import "../GSN/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.0; import "../GSN/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; }
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 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; } }
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.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; /** * @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)); } }
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); } }
{ "remappings": [], "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "istanbul", "libraries": {}, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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":[],"name":"UNDELEGATION_PROHIBITION_WINDOW_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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"}],"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":"validatorId","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"getDelegatedToValidator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"uint256","name":"validatorId","type":"uint256"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"getEffectiveDelegatedToValidator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorId","type":"uint256"}],"name":"getEffectiveDelegatedValuesByValidator","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
608060405234801561001057600080fd5b50615f3d80620000216000396000f3fe608060405234801561001057600080fd5b50600436106102325760003560e01c80635fd5529311610130578063a217fddf116100b8578063ca15c8731161007c578063ca15c873146104f6578063d547741f14610509578063dda641ae1461051c578063fa8dacba14610237578063ff1f77991461052f57610232565b8063a217fddf14610499578063b39e12cf146104a1578063b8631585146104a9578063c4336c1c146104bc578063c4d66de8146104e357610232565b806391d14854116100ff57806391d14854146104385780639654ff161461044b578063986b5d751461045e5780639ac1c4ad14610466578063a0fb47221461047957610232565b80635fd55293146103df5780637ce845d0146103f25780638fa6b518146104055780639010d07c1461041857610232565b806327040f68116101be5780633d42b1ce116101825780633d42b1ce14610373578063416880b01461038657806344c9af281461039957806356574b8c146103b95780635bb12446146103cc57610232565b806327040f681461030757806327e5455a1461031a5780632f2ff15d1461032d5780632f7263cd1461034057806336568abe1461036057610232565b80631d703812116102055780631d703812146102a85780631d9c7f0a146102bb5780631da42e5e146102ce57806321eb5859146102e1578063248a9ca3146102f457610232565b80630b975991146102375780630dd35701146102605780630e01bff8146102805780631c8a253e14610293575b600080fd5b61024a6102453660046152e8565b610542565b604051610257919061560d565b60405180910390f35b61027361026e36600461539f565b610555565b6040516102579190615e77565b61024a61028e36600461534b565b610698565b6102a66102a1366004615320565b6107c6565b005b61024a6102b636600461539f565b6107dc565b61024a6102c93660046153e6565b6107ef565b6102a66102dc3660046153e6565b61081d565b6102a66102ef36600461541f565b610cdc565b61024a61030236600461539f565b6110ab565b61024a6103153660046152e8565b6110c0565b6102a661032836600461539f565b6110cb565b6102a661033b3660046153b7565b61143c565b61035361034e3660046152e8565b611480565b6040516102579190615602565b6102a661036e3660046153b7565b6114b5565b61024a61038136600461539f565b6114f7565b61024a6103943660046153e6565b611509565b6103ac6103a736600461539f565b6116ba565b6040516102579190615616565b61024a6103c7366004615320565b61189d565b61024a6103da3660046153e6565b6118b6565b6102a66103ed3660046152e8565b6118dd565b61024a6104003660046152e8565b6118eb565b61024a6104133660046153e6565b611946565b61042b6104263660046153e6565b611964565b60405161025791906154f5565b6103536104463660046153b7565b611982565b61024a610459366004615320565b6119a0565b61024a6119cc565b6102a661047436600461539f565b6119d3565b61048c61048736600461539f565b611b26565b60405161025791906155be565b61024a611b40565b61042b611b45565b6102a66104b736600461539f565b611b54565b6104cf6104ca36600461539f565b611c3f565b604051610257989796959493929190615569565b6102a66104f13660046152e8565b611d28565b61024a61050436600461539f565b611db4565b6102a66105173660046153b7565b611dcb565b61024a61052a3660046152e8565b611e05565b61024a61053d366004615320565b611e20565b600061054d82611e34565b90505b919050565b61055d6151d1565b609854829081106105895760405162461bcd60e51b815260040161058090615cc7565b60405180910390fd5b6098838154811061059657fe5b600091825260209182902060408051610100808201835260089490940290920180546001600160a01b0316835260018082015484870152600280830154858501526003830154606086015260048301546080860152600583015460a0860152600683015460c08601526007830180548551938116159097026000190190961604601f81018790048702820187019093528281529294909360e08601939290918301828280156106865780601f1061065b57610100808354040283529160200191610686565b820191906000526020600020905b81548152906001019060200180831161066957829003601f168201915b50505050508152505091505b50919050565b604080518082018252600b81526a2234b9ba3934b13aba37b960a91b60208201526097549151633581777360e01b815260009233916001600160a01b03909116906335817773906106ed90859060040161562a565b60206040518083038186803b15801561070557600080fd5b505afa158015610719573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061073d9190615304565b6001600160a01b031614806107555750610755611e4b565b6107715760405162461bcd60e51b815260040161058090615d47565b606061077c86611e5d565b6001600160a01b038716600090815260a16020908152604080832089845290915290209091506107b2908563ffffffff611e6a16565b92506107bd81611fb1565b50509392505050565b6107d86107d383836121b1565b611fb1565b5050565b600061054d826107ea612471565b6124eb565b6099602052816000526040600020818154811061080857fe5b90600052602060002001600091509150505481565b6040805180820182526008815267283ab734b9b432b960c11b60208201526097549151633581777360e01b8152909133916001600160a01b039091169063358177739061086e90859060040161562a565b60206040518083038186803b15801561088657600080fd5b505afa15801561089a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108be9190615304565b6001600160a01b031614806108d657506108d6611e4b565b6108f25760405162461bcd60e51b815260040161058090615d47565b60006108fc612471565b905061090661521f565b6000858152609c6020526040902061092590858463ffffffff61250916565b6000868152609d6020526040812091925090610947908463ffffffff611e6a16565b604080516000808252602080830184528a8252609d9052919091206004015491925090841015610a47576000878152609d6020526040902060040154610993908563ffffffff6125db16565b67ffffffffffffffff811180156109a957600080fd5b506040519080825280602002602001820160405280156109d3578160200160208202803683370190505b50905060005b8151811015610a45576000888152609d6020526040812060019081019190610a1790610a0b898663ffffffff61261d16565b9063ffffffff61261d16565b815260200190815260200160002054828281518110610a3257fe5b60209081029190910101526001016109d9565b505b6000878152609d60205260409020610a6690848663ffffffff61264216565b6000878152609e60205260409020610a7f908486612792565b6040805160608101825284815260208082018a815292820187815260a280546001810182556000918252935180517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42d600490960295860155909201517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42e84015592517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42f83015591517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf43090910155610b5461288e565b6000898152609d602052604090209091506001600160a01b03821690635a4adb6890610b9790610b8a908963ffffffff611e6a16565b869063ffffffff6125db16565b876040518363ffffffff1660e01b8152600401610bb5929190615ee4565b600060405180830381600087803b158015610bcf57600080fd5b505af1158015610be3573d6000803e3d6000fd5b506000925050505b8251811015610cd1576000898152609d602052604081206001600160a01b03841691636ad5a9cf91610c6291600191820191610c3190610a0b8d8963ffffffff61261d16565b815260200190815260200160002054868581518110610c4c57fe5b60200260200101516125db90919063ffffffff16565b610c776001610a0b8b8763ffffffff61261d16565b6040518363ffffffff1660e01b8152600401610c94929190615ee4565b600060405180830381600087803b158015610cae57600080fd5b505af1158015610cc2573d6000803e3d6000fd5b50505050806001019050610beb565b505050505050505050565b610ce461290b565b6001600160a01b031663a795d293846040518263ffffffff1660e01b8152600401610d0f919061560d565b60206040518083038186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f919061537f565b610d7b5760405162461bcd60e51b815260040161058090615c31565b610d83612950565b6001600160a01b03166348b432a786866040518363ffffffff1660e01b8152600401610db0929190615ee4565b60006040518083038186803b158015610dc857600080fd5b505afa158015610ddc573d6000803e3d6000fd5b50505050610dea3386612995565b506060610df633611e5d565b90506000610e3d3388888888888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612aa292505050565b90506000609760009054906101000a90046001600160a01b03166001600160a01b0316639b391a466040518163ffffffff1660e01b815260040160206040518083038186803b158015610e8f57600080fd5b505afa158015610ea3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec79190615304565b6001600160a01b03166370a08231336040518263ffffffff1660e01b8152600401610ef291906154f5565b60206040518083038186803b158015610f0a57600080fd5b505afa158015610f1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f429190615407565b90506000609760009054906101000a90046001600160a01b03166001600160a01b031663ebd2665f6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f9457600080fd5b505afa158015610fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcc9190615304565b6001600160a01b0316630b975991336040518263ffffffff1660e01b8152600401610ff791906154f5565b602060405180830381600087803b15801561101157600080fd5b505af1158015611025573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110499190615407565b90508082101561106b5760405162461bcd60e51b81526004016105809061598b565b7f839237f8da6208af7e49773f22501b3082aaae94d5b6ce8ee96f117835fe2f678360405161109a919061560d565b60405180910390a1610cd184611fb1565b60009081526065602052604090206002015490565b600061054d82612d01565b609854819081106110ee5760405162461bcd60e51b815260040161058090615cc7565b60046110f9836116ba565b600681111561110457fe5b146111215760405162461bcd60e51b81526004016105809061591f565b600061112b612950565b9050336001600160a01b03166098848154811061114457fe5b60009182526020909120600890910201546001600160a01b0316148061128457506040516224441f60e71b81526001600160a01b038216906312220f80906111909033906004016154f5565b60206040518083038186803b1580156111a857600080fd5b505afa1580156111bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e0919061537f565b80156112845750604051630ba7341960e11b81526001600160a01b0382169063174e6832906112139033906004016154f5565b60206040518083038186803b15801561122b57600080fd5b505afa15801561123f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112639190615407565b6098848154811061127057fe5b906000526020600020906008020160010154145b6112a05760405162461bcd60e51b815260040161058090615cfe565b6112f2609884815481106112b057fe5b6000918252602090912060089091020154609880546001600160a01b0390921691869081106112db57fe5b906000526020600020906008020160010154612d3f565b6112fb336118dd565b61130483612e16565b6098848154811061131157fe5b90600052602060002090600802016006018190555061132e612f1d565b6001600160a01b031663568b55b26098858154811061134957fe5b9060005260206000209060080201600601546040518263ffffffff1660e01b8152600401611377919061560d565b60206040518083038186803b15801561138f57600080fd5b505afa1580156113a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c79190615407565b6113da426203f48063ffffffff61261d16565b106113f75760405162461bcd60e51b815260040161058090615db5565b61140083612f62565b7fb0142de902382ce87e0ae1e5ec0699b26d25bec2eeb06bca82e1253099b3119c8360405161142f919061560d565b60405180910390a1505050565b60008281526065602052604090206002015461145a90610446613332565b6114765760405162461bcd60e51b8152600401610580906156cf565b6107d88282613336565b600061148b826133a5565b801561054d57505060a2546001600160a01b0391909116600090815260a360205260409020541090565b6114bd613332565b6001600160a01b0316816001600160a01b0316146114ed5760405162461bcd60e51b815260040161058090615e28565b6107d882826133c2565b60009081526099602052604090205490565b6040805180820182526006815265426f756e747960d01b60208083019190915282518084018452600b81526a2234b9ba3934b13aba37b960a91b918101919091526097549251633581777360e01b815260009333916001600160a01b039091169063358177739061157e90869060040161562a565b60206040518083038186803b15801561159657600080fd5b505afa1580156115aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ce9190615304565b6001600160a01b031614806116695750609754604051633581777360e01b815233916001600160a01b03169063358177739061160e90859060040161562a565b60206040518083038186803b15801561162657600080fd5b505afa15801561163a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165e9190615304565b6001600160a01b0316145b806116775750611677611e4b565b6116935760405162461bcd60e51b815260040161058090615d47565b6000858152609d602052604090206116b1908563ffffffff611e6a16565b95945050505050565b609854600090829081106116e05760405162461bcd60e51b815260040161058090615cc7565b609883815481106116ed57fe5b906000526020600020906008020160050154600014156117f8576098838154811061171457fe5b906000526020600020906008020160060154600014156117ef57611736612f1d565b6001600160a01b031663bf64d8496098858154811061175157fe5b9060005260206000209060080201600401546040518263ffffffff1660e01b815260040161177f919061560d565b60206040518083038186803b15801561179757600080fd5b505afa1580156117ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117cf9190615407565b6117d7612471565b14156117e65760009150610692565b60039150610692565b60029150610692565b6098838154811061180557fe5b90600052602060002090600802016005015461181f612471565b101561182e5760019150610692565b6098838154811061183b57fe5b9060005260206000209060080201600601546000141561185e5760049150610692565b6098838154811061186b57fe5b906000526020600020906008020160060154611885612471565b10156118945760059150610692565b60069150610692565b609a602052816000526040600020818154811061080857fe5b6000828152609c602052604081206118d4908363ffffffff61343116565b90505b92915050565b6118e88160006107c6565b50565b6000806118f6612471565b6001600160a01b038416600090815260a56020526040902060010154909150811115611926576000915050610550565b50506001600160a01b038116600090815260a56020526040902054610550565b6000828152609d602052604081206118d4908363ffffffff6134f116565b60008281526065602052604081206118d4908363ffffffff6135a816565b60008281526065602052604081206118d4908363ffffffff6135b416565b6001600160a01b0391909116600090815260a46020908152604080832093835260019093019052205490565b6203f48081565b609854819081106119f65760405162461bcd60e51b815260040161058090615cc7565b60988281548110611a0357fe5b60009182526020909120600890910201546001600160a01b03163314611a3b5760405162461bcd60e51b81526004016105809061563d565b6000611a46836116ba565b6006811115611a5157fe5b14611a6e5760405162461bcd60e51b815260040161058090615b8d565b611a76612471565b60988381548110611a8357fe5b906000526020600020906008020160060181905550611aea60988381548110611aa857fe5b6000918252602090912060089091020154609880546001600160a01b039092169185908110611ad357fe5b9060005260206000209060080201600201546135c9565b507fc42cff898171c085fa87ecad4869a5fb22753dddf61048199b8c740c2109fb1182604051611b1a919061560d565b60405180910390a15050565b6000818152609d6020526040902060609061054d90613647565b600081565b6097546001600160a01b031681565b60985481908110611b775760405162461bcd60e51b815260040161058090615cc7565b611b7f612950565b6001600160a01b031663bed5012e3360988581548110611b9b57fe5b9060005260206000209060080201600101546040518363ffffffff1660e01b8152600401611bca929190615509565b60206040518083038186803b158015611be257600080fd5b505afa158015611bf6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1a919061537f565b611c365760405162461bcd60e51b815260040161058090615956565b6107d8826137fd565b60988181548110611c4c57fe5b60009182526020918290206008909102018054600180830154600280850154600386015460048701546005880154600689015460078a01805460408051601f6000199c841615610100029c909c0190921698909804998a018d90048d0281018d019097528887526001600160a01b039099169b5095999398929791969095949293830182828015611d1e5780601f10611cf357610100808354040283529160200191611d1e565b820191906000526020600020905b815481529060010190602001808311611d0157829003601f168201915b5050505050905088565b600054610100900460ff1680611d415750611d41613b70565b80611d4f575060005460ff16155b611d6b5760405162461bcd60e51b815260040161058090615afd565b600054610100900460ff16158015611d96576000805460ff1961ff0019909116610100171660011790555b611d9f82613b76565b80156107d8576000805461ff00191690555050565b600081815260656020526040812061054d90613c00565b600082815260656020526040902060020154611de990610446613332565b6114ed5760405162461bcd60e51b8152600401610580906158cf565b6001600160a01b03166000908152609a602052604090205490565b60006118d48383611e2f612471565b613c0b565b600061054d611e42836118eb565b610a0b84612d01565b6000611e578133611982565b90505b90565b606061054d8260006121b1565b6000826003015460001415611e81575060006118d7565b81836003015411611f9a5760038301545b828111611f825760008181526001808601602090815260408084205491889052832054611eff92611ef3919060028a01908690611ed690899063ffffffff6125db16565b81526020019081526020016000205461261d90919063ffffffff16565b9063ffffffff613c4616565b60008381526002870160205260409020549091508114611f2d57600082815260028601602052604090208190555b60008281526020869052604090205415611f51576000828152602086905260408120555b600082815260018601602052604090205415611f795760008281526001860160205260408120555b50600101611e92565b50611f9482600163ffffffff61261d16565b60038401555b506000908152600291909101602052604090205490565b60975460408051636f72c4ab60e01b815290516000926001600160a01b031691636f72c4ab916004808301926020929190829003018186803b158015611ff657600080fd5b505afa15801561200a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202e9190615304565b9050600080805b845181101561214357826001600160a01b031685828151811061205457fe5b6020026020010151600001516001600160a01b03161461210e5781156120d557604051634458328b60e01b81526001600160a01b03851690634458328b906120a29086908690600401615509565b600060405180830381600087803b1580156120bc57600080fd5b505af11580156120d0573d6000803e3d6000fd5b505050505b8481815181106120e157fe5b60200260200101516000015192508481815181106120fb57fe5b602002602001015160200151915061213b565b61213885828151811061211d57fe5b6020026020010151602001518361261d90919063ffffffff16565b91505b600101612035565b5080156121ab57604051634458328b60e01b81526001600160a01b03841690634458328b906121789085908590600401615509565b600060405180830381600087803b15801561219257600080fd5b505af11580156121a6573d6000803e3d6000fd5b505050505b50505050565b60606121bc83611480565b156118d7576001600160a01b038316600090815260a3602052604090205460a25483158015906121fa5750806121f8838663ffffffff61261d16565b105b156122125761220f828563ffffffff61261d16565b90505b612222818363ffffffff6125db16565b67ffffffffffffffff8111801561223857600080fd5b5060405190808252806020026020018201604052801561227257816020015b61225f615239565b8152602001906001900390816122575790505b509250815b8183101561245057600060a2848154811061228e57fe5b9060005260206000209060040201600201549050600060a285815481106122b157fe5b906000526020600020906004020160030154905060006122d2898484613c0b565b90506122e581600063ffffffff613c9916565b15612442576001600160a01b0389166000908152609f6020526040902060a280546123679291908990811061231657fe5b6000918252602080832060408051808201825260049094029091018054845260010154838301526001600160a01b038f16845260a0825280842089855290915290912091908563ffffffff613cb216565b6123c760a2878154811061237757fe5b6000918252602080832060408051808201825260049094029091018054845260010154838301526001600160a01b038e16845260a18252808420888552909152909120908463ffffffff61264216565b88876123d9888763ffffffff6125db16565b815181106123e357fe5b60209081029190910101516001600160a01b0390911690526124166124098a8585613c0b565b829063ffffffff613c4616565b87612427888763ffffffff6125db16565b8151811061243157fe5b602002602001015160200181815250505b505050826001019250612277565b506001600160a01b038516600090815260a360205260409020555092915050565b600061247b612f1d565b6001600160a01b031663ddd1b67e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156124b357600080fd5b505afa1580156124c7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e579190615407565b6000828152609c602052604081206118d4908363ffffffff613cc016565b61251161521f565b600384015461252783600163ffffffff61261d16565b10156125455760405162461bcd60e51b81526004016105809061571e565b600384015461255f576125586000613de3565b90506125d4565b600061256b8584613cc0565b905061257e81600063ffffffff613df616565b156125955761258d6000613de3565b9150506125d4565b83808210156125a15750805b6125a961521f565b6125c26125bc848463ffffffff613c4616565b84613e1c565b90506125cf878287613e6c565b925050505b9392505050565b60006118d483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613e7a565b6000828201838110156118d45760405162461bcd60e51b8152600401610580906157e4565b600383015461265882600163ffffffff61261d16565b10156126765760405162461bcd60e51b81526004016105809061571e565b60208201518251111561269b5760405162461bcd60e51b815260040161058090615755565b60038301546126a95761278d565b60006126b58483611e6a565b90506126c881600063ffffffff613df616565b156126d3575061278d565b602080840151845160008581526002880190935260409092205461270d92612701919063ffffffff613ea616565b9063ffffffff613ee016565b600083815260028601602052604081209190915561273283600163ffffffff61261d16565b90505b8460040154811161278a57602080850151855160008481526001890190935260409092205461276e92612701919063ffffffff613ea616565b6000828152600180880160205260409091209190915501612735565b50505b505050565b60018301546127d05760018084018290556002808501839055600083815260208681526040822086518155908601519381019390935591015561278d565b80836002015411156127f45760405162461bcd60e51b815260040161058090615ab8565b808360020154141561285557600081815260208481526040918290208251808401909352805483526001015490820152612834908363ffffffff613f2216565b6000828152602085815260409091208251815591015160019091015561278d565b60008181526020848152604080832085518155918501516001830155600291820183905581860180548452922001829055819055505050565b6097546040805163f49bff7b60e01b815290516000926001600160a01b03169163f49bff7b916004808301926020929190829003018186803b1580156128d357600080fd5b505afa1580156128e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e579190615304565b609754604080516323f9e0d960e11b815290516000926001600160a01b0316916347f3c1b2916004808301926020929190829003018186803b1580156128d357600080fd5b60975460408051639cb83f5760e01b815290516000926001600160a01b031691639cb83f57916004808301926020929190829003018186803b1580156128d357600080fd5b6001600160a01b038216600090815260a660209081526040808320848452600101909152812054151580612a8657506001600160a01b038316600090815260a660209081526040808320858452600101909152902054158015612a8657506129fb613f60565b6001600160a01b031663049e41776040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3357600080fd5b505afa158015612a47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6b9190615407565b6001600160a01b038416600090815260a66020526040902054105b6118d75760405162461bcd60e51b815260040161058090615d7e565b6098805460408051610100810182526001600160a01b03898116825260208083018a8152938301898152606084018981524260808601908152600060a0870181815260c0880182815260e089018d815260018c018d559b90925287517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81460088c0290810180546001600160a01b0319169290991691909117885598517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d8158a015593517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81689015591517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d817880155517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81887015590517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d819860155517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81a85015594518051949592949193612c59937f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81b90910192910190615250565b5050506000858152609960209081526040808320805460018181018355918552838520018590556001600160a01b038a168452609a835290832080549182018155835291200181905560988054612cf7919083908110612cb557fe5b6000918252602090912060089091020154609880546001600160a01b039092169184908110612ce057fe5b906000526020600020906008020160020154613fa5565b5095945050505050565b600080612d0c612471565b9050612d17836118dd565b6001600160a01b0383166000908152609f602052604090206125d4908263ffffffff613cc016565b6001600160a01b038216600090815260a6602090815260408083208484526001908101909252909120541415612db3576001600160a01b038216600090815260a66020526040902054612d9990600163ffffffff6125db16565b6001600160a01b038316600090815260a660205260409020555b6001600160a01b038216600090815260a660209081526040808320848452600190810190925290912054612dec9163ffffffff6125db16565b6001600160a01b03909216600090815260a660209081526040808320938352600190930190522055565b600080612e21612471565b9050600060988481548110612e3257fe5b906000526020600020906008020160050154905080821015612e8857612e7f60988581548110612e5e57fe5b9060005260206000209060080201600301548261261d90919063ffffffff16565b92505050610550565b6000612ebf60988681548110612e9a57fe5b90600052602060002090600802016003015461270184866125db90919063ffffffff16565b9050612f13612f0660988781548110612ed457fe5b906000526020600020906008020160030154612efa60018561261d90919063ffffffff16565b9063ffffffff613ea616565b839063ffffffff61261d16565b9350505050610550565b6097546040805163954b385d60e01b815290516000926001600160a01b03169163954b385d916004808301926020929190829003018186803b1580156128d357600080fd5b6000612f6d82614050565b9050612fb660988381548110612f7f57fe5b9060005260206000209060080201600101548260988581548110612f9f57fe5b906000526020600020906008020160060154614189565b61301060988381548110612fc657fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b03168260988581548110612ff957fe5b9060005260206000209060080201600601546141a8565b6130826098838154811061302057fe5b6000918252602090912060089091020154609880546001600160a01b03909216918590811061304b57fe5b906000526020600020906008020160010154836098868154811061306b57fe5b9060005260206000209060080201600601546141d1565b600061313561308f61290b565b6001600160a01b031663f5b98f41609886815481106130aa57fe5b9060005260206000209060080201600301546040518263ffffffff1660e01b81526004016130d8919061560d565b60206040518083038186803b1580156130f057600080fd5b505afa158015613104573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131289190615407565b839063ffffffff613ea616565b905061317e6098848154811061314757fe5b906000526020600020906008020160010154826098868154811061316757fe5b906000526020600020906008020160060154614205565b6131f06098848154811061318e57fe5b6000918252602090912060089091020154609880546001600160a01b0390921691869081106131b957fe5b90600052602060002090600802016001015483609887815481106131d957fe5b906000526020600020906008020160060154614224565b6131f8614258565b6001600160a01b0316630d4e8fd16098858154811061321357fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b0316856098878154811061324657fe5b9060005260206000209060080201600601546040518463ffffffff1660e01b815260040161327693929190615522565b600060405180830381600087803b15801561329057600080fd5b505af11580156132a4573d6000803e3d6000fd5b505050506132b061288e565b6001600160a01b0316635a4adb6882609886815481106132cc57fe5b9060005260206000209060080201600601546040518363ffffffff1660e01b81526004016132fb929190615ee4565b600060405180830381600087803b15801561331557600080fd5b505af1158015613329573d6000803e3d6000fd5b50505050505050565b3390565b6000828152606560205260409020613354908263ffffffff61429d16565b156107d857613361613332565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0316600090815260a46020526040902054151590565b60008281526065602052604090206133e0908263ffffffff6142b216565b156107d8576133ed613332565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b600382015460009061344a83600163ffffffff61261d16565b10156134685760405162461bcd60e51b81526004016105809061584b565b6003830154613479575060006118d7565b818360030154116134e657600283015460038401545b8381116134de57600081815260018601602090815260408083205491889052909120546134d491906134c890859063ffffffff61261d16565b9063ffffffff6125db16565b915060010161348f565b5090506118d7565b5060028201546118d7565b6000826003015460001415613508575060006118d7565b81836003015411613591576000836002016000613533600187600301546125db90919063ffffffff16565b81526020019081526020016000205490506000846003015490505b8381116134de576000818152600186016020908152604080832054918890529091205461358791906134c890859063ffffffff61261d16565b915060010161354e565b5060008181526002830160205260409020546118d7565b60006118d483836142c7565b60006118d4836001600160a01b03841661430c565b6000806135d4612471565b6001600160a01b038516600090815260a5602052604090206001015490915081146135fb57fe5b6001600160a01b038416600090815260a56020526040902054613624908463ffffffff6125db16565b6001600160a01b03909416600090815260a5602052604090209390935592915050565b606081600301546000141561365b57610550565b600382015460009061367490600163ffffffff6125db16565b905060006136906001856004015461261d90919063ffffffff16565b90508181116136ad576136aa82600163ffffffff61261d16565b90505b6136bd818363ffffffff6125db16565b67ffffffffffffffff811180156136d357600080fd5b506040519080825280602002602001820160405280156136fd578160200160208202803683370190505b50925083600201600061371e600187600301546125db90919063ffffffff16565b8152602001908152602001600020548360008151811061373a57fe5b602090810291909101015260005b835161375b82600163ffffffff61261d16565b10156137f5576003850154600090613779908363ffffffff61261d16565b6000818152600188016020908152604080832054918a90529091205487519293506137c5926134c891908990879081106137af57fe5b602002602001015161261d90919063ffffffff16565b856137d784600163ffffffff61261d16565b815181106137e157fe5b602090810291909101015250600101613748565b505050919050565b61384f6098828154811061380d57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918490811061383857fe5b906000526020600020906008020160010154612995565b50600061385b826116ba565b9050600081600681111561386b57fe5b1461393657600181600681111561387e57fe5b14806138955750600481600681111561389357fe5b145b806138ab575060058160068111156138a957fe5b145b806138c1575060068160068111156138bf57fe5b145b156138de5760405162461bcd60e51b81526004016105809061579c565b60028160068111156138ec57fe5b141561390a5760405162461bcd60e51b815260040161058090615c76565b600381600681111561391857fe5b14156139365760405162461bcd60e51b81526004016105809061588d565b600081600681111561394457fe5b146139615760405162461bcd60e51b815260040161058090615bea565b60606139926098848154811061397357fe5b60009182526020909120600890910201546001600160a01b0316611e5d565b905061399d83614324565b6000609884815481106139ac57fe5b90600052602060002090600802016002015490506139c8614258565b6001600160a01b03166394df393f609886815481106139e357fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b0316868460988981548110613a1757fe5b9060005260206000209060080201600501546040518563ffffffff1660e01b8152600401613a489493929190615543565b600060405180830381600087803b158015613a6257600080fd5b505af1158015613a76573d6000803e3d6000fd5b505050506000613aa2613a8761290b565b6001600160a01b031663f5b98f41609888815481106130aa57fe5b9050613aac61288e565b6001600160a01b0316636ad5a9cf8260988881548110613ac857fe5b9060005260206000209060080201600501546040518363ffffffff1660e01b8152600401613af7929190615ee4565b600060405180830381600087803b158015613b1157600080fd5b505af1158015613b25573d6000803e3d6000fd5b50505050613b3283611fb1565b7fdb0c41de0e1a6e61f3ea29d9618edd8bfe8cb4e041a267c54eec70418341272d85604051613b61919061560d565b60405180910390a15050505050565b303b1590565b600054610100900460ff1680613b8f5750613b8f613b70565b80613b9d575060005460ff16155b613bb95760405162461bcd60e51b815260040161058090615afd565b600054610100900460ff16158015613be4576000805460ff1961ff0019909116610100171660011790555b613bec61475c565b613bf7600033611476565b611d9f826147ee565b600061054d82614864565b6001600160a01b038316600090815260a0602090815260408083208584529091528120613c3e908363ffffffff613cc016565b949350505050565b6000818310613c5857508082036118d7565b7f5b70a077a991facb623c7b2ee44cc539dc6ba345b6636552b8ea97fbbd4d54198383604051613c89929190615ee4565b60405180910390a15060006118d7565b6000620f4240198210613ca857fe5b50620f4240011090565b6121ab848484846001614868565b6003820154600090613cd983600163ffffffff61261d16565b1015613cf75760405162461bcd60e51b81526004016105809061584b565b6003830154613d08575060006118d7565b81836003015411613dda57600283015460038401545b838111613dae5760008181526001860160209081526040808320549188905290912054613d579190611ef390859063ffffffff61261d16565b60008281526020879052604090205490925015613d7e576000818152602086905260408120555b600081815260018601602052604090205415613da65760008181526001860160205260408120555b600101613d1e565b5080846002015414613dc257600284018190555b613dd383600163ffffffff61261d16565b6003850155505b50506002015490565b613deb61521f565b61054d826001613e1c565b600081831115613e0e5750620f4240818303106118d7565b50620f4240828203106118d7565b613e2461521f565b60008211613e445760405162461bcd60e51b815260040161058090615a57565b613e4c61521f565b60405180604001604052808581526020018481525090506118d481614a4f565b61278d838484846000614868565b60008184841115613e9e5760405162461bcd60e51b8152600401610580919061562a565b505050900390565b600082613eb5575060006118d7565b82820282848281613ec257fe5b04146118d45760405162461bcd60e51b8152600401610580906159df565b60006118d483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614a9b565b613f2a61521f565b815183516118d491613f42919063ffffffff613ea616565b60208085015190860151613f5b9163ffffffff613ea616565b613e1c565b60975460408051633f2a95e960e21b815290516000926001600160a01b03169163fcaa57a4916004808301926020929190829003018186803b1580156128d357600080fd5b600080613fb0612471565b6001600160a01b038516600090815260a56020526040902060010154909150811115613ffc576001600160a01b038416600090815260a560205260409020838155600101819055614049565b6001600160a01b038416600090815260a56020526040902060010154811461402057fe5b6001600160a01b038416600090815260a56020526040902054613624908463ffffffff61261d16565b5092915050565b6000818152609b6020526040812054609880548391908590811061407057fe5b906000526020600020906008020160010154905060006098858154811061409357fe5b906000526020600020906008020160020154905082600014156140d3576000828152609e60205260409020600101549250826140d3579250610550915050565b825b6000811180156141025750609886815481106140ed57fe5b90600052602060002090600802016006015481105b15614180576098868154811061411457fe5b906000526020600020906008020160050154811061415f576000838152609e6020908152604080832084845290915290206001810154905461415c9190612701908590613ea6565b91505b6000838152609e6020908152604080832093835292905220600201546140d5565b50949350505050565b6000838152609c6020526040902061278d90838363ffffffff614ad216565b6001600160a01b0383166000908152609f6020526040902061278d90838363ffffffff614ad216565b6001600160a01b038416600090815260a06020908152604080832086845290915290206121ab90838363ffffffff614ad216565b6000838152609d6020526040902061278d90838363ffffffff614b9316565b6001600160a01b038416600090815260a16020908152604080832086845290915290206121ab90838363ffffffff614b9316565b6097546040805163541a252760e01b815290516000926001600160a01b03169163541a2527916004808301926020929190829003018186803b1580156128d357600080fd5b60006118d4836001600160a01b038416614c11565b60006118d4836001600160a01b038416614c5b565b815460009082106142ea5760405162461bcd60e51b81526004016105809061568d565b8260000182815481106142f957fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b600061432e612471565b905061434181600163ffffffff61261d16565b6098838154811061434e57fe5b9060005260206000209060080201600501819055506000609e60006098858154811061437657fe5b90600052602060002090600802016001015481526020019081526020016000206002015411156143e757609e6000609884815481106143b157fe5b60009182526020808320600160089093020191909101548352828101939093526040918201812060020154858252609b90935220555b614441609883815481106143f757fe5b9060005260206000209060080201600101546098848154811061441657fe5b90600052602060002090600802016002015461443c60018561261d90919063ffffffff16565b614d21565b6144a76098838154811061445157fe5b6000918252602090912060089091020154609880546001600160a01b03909216918590811061447c57fe5b9060005260206000209060080201600201546144a260018561261d90919063ffffffff16565b614d40565b61452c609883815481106144b757fe5b6000918252602090912060089091020154609880546001600160a01b0390921691859081106144e257fe5b9060005260206000209060080201600101546098858154811061450157fe5b90600052602060002090600802016002015461452760018661261d90919063ffffffff16565b614d69565b6145926098838154811061453c57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918590811061456757fe5b90600052602060002090600802016001015461458d60018561261d90919063ffffffff16565b614d9d565b600061466561459f61290b565b6001600160a01b031663f5b98f41609886815481106145ba57fe5b9060005260206000209060080201600301546040518263ffffffff1660e01b81526004016145e8919061560d565b60206040518083038186803b15801561460057600080fd5b505afa158015614614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146389190615407565b6098858154811061464557fe5b906000526020600020906008020160020154613ea690919063ffffffff16565b90506146a36098848154811061467757fe5b9060005260206000209060080201600101548261469e60018661261d90919063ffffffff16565b614e3b565b61470a609884815481106146b357fe5b6000918252602090912060089091020154609880546001600160a01b0390921691869081106146de57fe5b9060005260206000209060080201600101548361470560018761261d90919063ffffffff16565b614e5a565b61278d6098848154811061471a57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918690811061474557fe5b906000526020600020906008020160010154614e8e565b600054610100900460ff16806147755750614775613b70565b80614783575060005460ff16155b61479f5760405162461bcd60e51b815260040161058090615afd565b600054610100900460ff161580156147ca576000805460ff1961ff0019909116610100171660011790555b6147d2614f36565b6147da614f36565b80156118e8576000805461ff001916905550565b6001600160a01b0381166148145760405162461bcd60e51b815260040161058090615b4b565b614826816001600160a01b0316614fb7565b6148425760405162461bcd60e51b815260040161058090615a20565b609780546001600160a01b0319166001600160a01b0392909216919091179055565b5490565b600385015461487e83600163ffffffff61261d16565b101561489c5760405162461bcd60e51b81526004016105809061571e565b80156148d65760038401546148b883600163ffffffff61261d16565b10156148d65760405162461bcd60e51b81526004016105809061571e565b6020830151835111156148fb5760405162461bcd60e51b815260040161058090615755565b60038501546149095761278a565b60006149158684613cc0565b905061492881600063ffffffff613df616565b15614933575061278a565b6000614958856020015161270187600001518a60020154613ea690919063ffffffff16565b90508215614981576149818661497b838a60020154613c4690919063ffffffff16565b86614ad2565b60028701819055600061499b85600163ffffffff61261d16565b90505b876004015481116121a6576020808701518751600084815260018c0190935260408320546149d79291612701919063ffffffff613ea616565b90508415614a3357600082815260018a016020526040902054614a2190614a04908363ffffffff613c4616565b600084815260018b0160205260409020549063ffffffff613c4616565b600083815260018a0160205260409020555b60008281526001808b016020526040909120919091550161499e565b6000614a6382600001518360200151614ff0565b8251909150614a78908263ffffffff613ee016565b82526020820151614a8f908263ffffffff613ee016565b60209092019190915250565b60008183614abc5760405162461bcd60e51b8152600401610580919061562a565b506000838581614ac857fe5b0495945050505050565b614ae381600163ffffffff61261d16565b83600301541115614b065760405162461bcd60e51b815260040161058090615a81565b6003830154614b1e5760038301819055600483018190555b8260040154811115614b3257600483018190555b82600301548110614b74576000818152600184016020526040902054614b5e908363ffffffff61261d16565b600082815260018501602052604090205561278d565b6002830154614b89908363ffffffff613c4616565b6002840155505050565b8083600301541115614bb75760405162461bcd60e51b815260040161058090615a81565b6003830154614bc857600383018190555b6000818152600184016020526040902054614be9908363ffffffff61261d16565b60008281526001850160205260409020556004830154811461278d5760048301819055505050565b6000614c1d838361430c565b614c53575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556118d7565b5060006118d7565b60008181526001830160205260408120548015614d175783546000198083019190810190600090879083908110614c8e57fe5b9060005260206000200154905080876000018481548110614cab57fe5b600091825260208083209091019290925582815260018981019092526040902090840190558654879080614cdb57fe5b600190038181906000526020600020016000905590558660010160008781526020019081526020016000206000905560019450505050506118d7565b60009150506118d7565b6000838152609c6020526040902061278d90838363ffffffff61504016565b6001600160a01b0383166000908152609f6020526040902061278d90838363ffffffff61504016565b6001600160a01b038416600090815260a06020908152604080832086845290915290206121ab90838363ffffffff61504016565b6001600160a01b038316600090815260a46020526040902054614de5576001600160a01b038316600090815260a46020908152604080832084905560a25460a3909252909120555b6001600160a01b038316600090815260a46020908152604080832085845260010190915290205461278d576001600160a01b0392909216600090815260a460209081526040808320938352600190930190522055565b6000838152609d6020526040902061278d90838363ffffffff6150e316565b6001600160a01b038416600090815260a16020908152604080832086845290915290206121ab90838363ffffffff6150e316565b6001600160a01b038216600090815260a660209081526040808320848452600101909152902054614efd576001600160a01b038216600090815260a66020526040902054614ee390600163ffffffff61261d16565b6001600160a01b038316600090815260a660205260409020555b6001600160a01b038216600090815260a660209081526040808320848452600190810190925290912054612dec9163ffffffff61261d16565b600054610100900460ff1680614f4f5750614f4f613b70565b80614f5d575060005460ff16155b614f795760405162461bcd60e51b815260040161058090615afd565b600054610100900460ff161580156147da576000805460ff1961ff00199091166101001716600117905580156118e8576000805461ff001916905550565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590613c3e575050151592915050565b600082828181111561500c57615006828261515d565b90925090505b801561503857615022828263ffffffff61516016565b915061502e828261515d565b909250905061500c565b509392505050565b80836003015411156150645760405162461bcd60e51b81526004016105809061581b565b600383015461507c5760038301819055600483018190555b826004015481111561509057600483018190555b826003015481106150ce576000818152602084905260409020546150ba908363ffffffff61261d16565b60008281526020859052604090205561278d565b6002830154614b89908363ffffffff61261d16565b80836003015411156151075760405162461bcd60e51b81526004016105809061581b565b600383015461511857600383018190555b600081815260208490526040902054615137908363ffffffff61261d16565b6000828152602085905260409020556004830154811461278d5760048301819055505050565b91565b60006118d483836040518060400160405280601881526020017f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000815250600081836151be5760405162461bcd60e51b8152600401610580919061562a565b508284816151c857fe5b06949350505050565b60405180610100016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081525090565b604051806040016040528060008152602001600081525090565b604080518082019091526000808252602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061529157805160ff19168380011785556152be565b828001600101855582156152be579182015b828111156152be5782518255916020019190600101906152a3565b506152ca9291506152ce565b5090565b611e5a91905b808211156152ca57600081556001016152d4565b6000602082840312156152f9578081fd5b81356118d481615ef2565b600060208284031215615315578081fd5b81516118d481615ef2565b60008060408385031215615332578081fd5b823561533d81615ef2565b946020939093013593505050565b60008060006060848603121561535f578081fd5b833561536a81615ef2565b95602085013595506040909401359392505050565b600060208284031215615390578081fd5b815180151581146118d4578182fd5b6000602082840312156153b0578081fd5b5035919050565b600080604083850312156153c9578182fd5b8235915060208301356153db81615ef2565b809150509250929050565b600080604083850312156153f8578182fd5b50508035926020909101359150565b600060208284031215615418578081fd5b5051919050565b600080600080600060808688031215615436578081fd5b853594506020860135935060408601359250606086013567ffffffffffffffff80821115615462578283fd5b81880189601f820112615473578384fd5b8035925081831115615483578384fd5b896020848301011115615494578384fd5b6020810194505050809150509295509295909350565b60008151808452815b818110156154cf576020818501810151868301820152016154b3565b818111156154e05782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b600061010060018060a01b038b1683528960208401528860408401528760608401528660808401528560a08401528460c08401528060e08401526155af818401856154aa565b9b9a5050505050505050505050565b6020808252825182820181905260009190848201906040850190845b818110156155f6578351835292840192918401916001016155da565b50909695505050505050565b901515815260200190565b90815260200190565b602081016007831061562457fe5b91905290565b6000602082526118d460208301846154aa565b60208082526030908201527f4f6e6c7920746f6b656e20686f6c646572732063616e2063616e63656c20646560408201526f1b1959d85d1a5bdb881c995c5d595cdd60821b606082015260800190565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252602f908201527f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60408201526e0818591b5a5b881d1bc819dc985b9d608a1b606082015260800190565b6020808252601f908201527f43616e6e6f74207265647563652076616c756520696e20746865207061737400604082015260600190565b60208082526027908201527f496e6372656173696e67206f662076616c756573206973206e6f7420696d706c604082015266195b595b9d195960ca1b606082015260800190565b60208082526028908201527f5468652064656c65676174696f6e20686173206265656e20616c7265616479206040820152671858d8d95c1d195960c21b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526016908201527510d85b9b9bdd08185919081d1bc81d1a19481c185cdd60521b604082015260600190565b60208082526022908201527f43616e6e6f742063616c63756c6174652076616c756520696e207468652070616040820152611cdd60f21b606082015260800190565b60208082526022908201527f5468652064656c65676174696f6e2072657175657374206973206f7574646174604082015261195960f21b606082015260800190565b60208082526030908201527f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60408201526f2061646d696e20746f207265766f6b6560801b606082015260800190565b6020808252601b908201527f43616e6e6f74207265717565737420756e64656c65676174696f6e0000000000604082015260600190565b6020808252818101527f4e6f207065726d697373696f6e7320746f206163636570742072657175657374604082015260600190565b60208082526034908201527f546f6b656e20686f6c64657220646f6573206e6f74206861766520656e6f75676040820152736820746f6b656e7320746f2064656c656761746560601b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527f41646472657373206973206e6f7420636f6e7472616374000000000000000000604082015260600190565b60208082526010908201526f4469766973696f6e206279207a65726f60801b604082015260600190565b6020808252601d908201527f43616e6e6f742073756274726163742066726f6d207468652070617374000000604082015260600190565b60208082526025908201527f43616e6e6f742070757420736c617368696e67206576656e7420696e20746865604082015264081c185cdd60da1b606082015260800190565b6020808252602e908201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560408201526d195b881a5b9a5d1a585b1a5e995960921b606082015260800190565b60208082526022908201527f436f6e74726163744d616e616765722061646472657373206973206e6f742073604082015261195d60f21b606082015260800190565b6020808252603a908201527f546f6b656e20686f6c6465727320617265206f6e6c792061626c6520746f206360408201527f616e63656c2050524f504f5345442064656c65676174696f6e73000000000000606082015260800190565b60208082526027908201527f43616e6e6f74207365742064656c65676174696f6e20737461746520746f206160408201526618d8d95c1d195960ca1b606082015260800190565b60208082526025908201527f546869732064656c65676174696f6e20706572696f64206973206e6f7420616c6040820152641b1bddd95960da1b606082015260800190565b60208082526031908201527f5468652064656c65676174696f6e20686173206265656e2063616e63656c6c656040820152703210313c903a37b5b2b7103437b63232b960791b606082015260800190565b60208082526019908201527f44656c65676174696f6e20646f6573206e6f7420657869737400000000000000604082015260600190565b60208082526029908201527f5065726d697373696f6e2064656e69656420746f207265717565737420756e6460408201526832b632b3b0ba34b7b760b91b606082015260800190565b60208082526019908201527f4d6573736167652073656e64657220697320696e76616c696400000000000000604082015260600190565b6020808252601e908201527f4c696d6974206f662076616c696461746f727320697320726561636865640000604082015260600190565b6020808252604d908201527f556e64656c65676174696f6e207265717565737473206d75737420626520736560408201527f6e7420332064617973206265666f72652074686520656e64206f662064656c6560608201526c19d85d1a5bdb881c195c9a5bd9609a1b608082015260a00190565b6020808252602f908201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560408201526e103937b632b9903337b91039b2b63360891b606082015260800190565b60006020825260018060a01b038351166020830152602083015160408301526040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e0830151610100808185015250613c3e6101208401826154aa565b918252602082015260400190565b6001600160a01b03811681146118e857600080fdfea26469706673582212202b07a6c506eb6d89666a5ba1fd6c0c95af96f1573f9b9d64ae12b450d671511964736f6c634300060a0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102325760003560e01c80635fd5529311610130578063a217fddf116100b8578063ca15c8731161007c578063ca15c873146104f6578063d547741f14610509578063dda641ae1461051c578063fa8dacba14610237578063ff1f77991461052f57610232565b8063a217fddf14610499578063b39e12cf146104a1578063b8631585146104a9578063c4336c1c146104bc578063c4d66de8146104e357610232565b806391d14854116100ff57806391d14854146104385780639654ff161461044b578063986b5d751461045e5780639ac1c4ad14610466578063a0fb47221461047957610232565b80635fd55293146103df5780637ce845d0146103f25780638fa6b518146104055780639010d07c1461041857610232565b806327040f68116101be5780633d42b1ce116101825780633d42b1ce14610373578063416880b01461038657806344c9af281461039957806356574b8c146103b95780635bb12446146103cc57610232565b806327040f681461030757806327e5455a1461031a5780632f2ff15d1461032d5780632f7263cd1461034057806336568abe1461036057610232565b80631d703812116102055780631d703812146102a85780631d9c7f0a146102bb5780631da42e5e146102ce57806321eb5859146102e1578063248a9ca3146102f457610232565b80630b975991146102375780630dd35701146102605780630e01bff8146102805780631c8a253e14610293575b600080fd5b61024a6102453660046152e8565b610542565b604051610257919061560d565b60405180910390f35b61027361026e36600461539f565b610555565b6040516102579190615e77565b61024a61028e36600461534b565b610698565b6102a66102a1366004615320565b6107c6565b005b61024a6102b636600461539f565b6107dc565b61024a6102c93660046153e6565b6107ef565b6102a66102dc3660046153e6565b61081d565b6102a66102ef36600461541f565b610cdc565b61024a61030236600461539f565b6110ab565b61024a6103153660046152e8565b6110c0565b6102a661032836600461539f565b6110cb565b6102a661033b3660046153b7565b61143c565b61035361034e3660046152e8565b611480565b6040516102579190615602565b6102a661036e3660046153b7565b6114b5565b61024a61038136600461539f565b6114f7565b61024a6103943660046153e6565b611509565b6103ac6103a736600461539f565b6116ba565b6040516102579190615616565b61024a6103c7366004615320565b61189d565b61024a6103da3660046153e6565b6118b6565b6102a66103ed3660046152e8565b6118dd565b61024a6104003660046152e8565b6118eb565b61024a6104133660046153e6565b611946565b61042b6104263660046153e6565b611964565b60405161025791906154f5565b6103536104463660046153b7565b611982565b61024a610459366004615320565b6119a0565b61024a6119cc565b6102a661047436600461539f565b6119d3565b61048c61048736600461539f565b611b26565b60405161025791906155be565b61024a611b40565b61042b611b45565b6102a66104b736600461539f565b611b54565b6104cf6104ca36600461539f565b611c3f565b604051610257989796959493929190615569565b6102a66104f13660046152e8565b611d28565b61024a61050436600461539f565b611db4565b6102a66105173660046153b7565b611dcb565b61024a61052a3660046152e8565b611e05565b61024a61053d366004615320565b611e20565b600061054d82611e34565b90505b919050565b61055d6151d1565b609854829081106105895760405162461bcd60e51b815260040161058090615cc7565b60405180910390fd5b6098838154811061059657fe5b600091825260209182902060408051610100808201835260089490940290920180546001600160a01b0316835260018082015484870152600280830154858501526003830154606086015260048301546080860152600583015460a0860152600683015460c08601526007830180548551938116159097026000190190961604601f81018790048702820187019093528281529294909360e08601939290918301828280156106865780601f1061065b57610100808354040283529160200191610686565b820191906000526020600020905b81548152906001019060200180831161066957829003601f168201915b50505050508152505091505b50919050565b604080518082018252600b81526a2234b9ba3934b13aba37b960a91b60208201526097549151633581777360e01b815260009233916001600160a01b03909116906335817773906106ed90859060040161562a565b60206040518083038186803b15801561070557600080fd5b505afa158015610719573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061073d9190615304565b6001600160a01b031614806107555750610755611e4b565b6107715760405162461bcd60e51b815260040161058090615d47565b606061077c86611e5d565b6001600160a01b038716600090815260a16020908152604080832089845290915290209091506107b2908563ffffffff611e6a16565b92506107bd81611fb1565b50509392505050565b6107d86107d383836121b1565b611fb1565b5050565b600061054d826107ea612471565b6124eb565b6099602052816000526040600020818154811061080857fe5b90600052602060002001600091509150505481565b6040805180820182526008815267283ab734b9b432b960c11b60208201526097549151633581777360e01b8152909133916001600160a01b039091169063358177739061086e90859060040161562a565b60206040518083038186803b15801561088657600080fd5b505afa15801561089a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108be9190615304565b6001600160a01b031614806108d657506108d6611e4b565b6108f25760405162461bcd60e51b815260040161058090615d47565b60006108fc612471565b905061090661521f565b6000858152609c6020526040902061092590858463ffffffff61250916565b6000868152609d6020526040812091925090610947908463ffffffff611e6a16565b604080516000808252602080830184528a8252609d9052919091206004015491925090841015610a47576000878152609d6020526040902060040154610993908563ffffffff6125db16565b67ffffffffffffffff811180156109a957600080fd5b506040519080825280602002602001820160405280156109d3578160200160208202803683370190505b50905060005b8151811015610a45576000888152609d6020526040812060019081019190610a1790610a0b898663ffffffff61261d16565b9063ffffffff61261d16565b815260200190815260200160002054828281518110610a3257fe5b60209081029190910101526001016109d9565b505b6000878152609d60205260409020610a6690848663ffffffff61264216565b6000878152609e60205260409020610a7f908486612792565b6040805160608101825284815260208082018a815292820187815260a280546001810182556000918252935180517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42d600490960295860155909201517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42e84015592517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42f83015591517faaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf43090910155610b5461288e565b6000898152609d602052604090209091506001600160a01b03821690635a4adb6890610b9790610b8a908963ffffffff611e6a16565b869063ffffffff6125db16565b876040518363ffffffff1660e01b8152600401610bb5929190615ee4565b600060405180830381600087803b158015610bcf57600080fd5b505af1158015610be3573d6000803e3d6000fd5b506000925050505b8251811015610cd1576000898152609d602052604081206001600160a01b03841691636ad5a9cf91610c6291600191820191610c3190610a0b8d8963ffffffff61261d16565b815260200190815260200160002054868581518110610c4c57fe5b60200260200101516125db90919063ffffffff16565b610c776001610a0b8b8763ffffffff61261d16565b6040518363ffffffff1660e01b8152600401610c94929190615ee4565b600060405180830381600087803b158015610cae57600080fd5b505af1158015610cc2573d6000803e3d6000fd5b50505050806001019050610beb565b505050505050505050565b610ce461290b565b6001600160a01b031663a795d293846040518263ffffffff1660e01b8152600401610d0f919061560d565b60206040518083038186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5f919061537f565b610d7b5760405162461bcd60e51b815260040161058090615c31565b610d83612950565b6001600160a01b03166348b432a786866040518363ffffffff1660e01b8152600401610db0929190615ee4565b60006040518083038186803b158015610dc857600080fd5b505afa158015610ddc573d6000803e3d6000fd5b50505050610dea3386612995565b506060610df633611e5d565b90506000610e3d3388888888888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612aa292505050565b90506000609760009054906101000a90046001600160a01b03166001600160a01b0316639b391a466040518163ffffffff1660e01b815260040160206040518083038186803b158015610e8f57600080fd5b505afa158015610ea3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec79190615304565b6001600160a01b03166370a08231336040518263ffffffff1660e01b8152600401610ef291906154f5565b60206040518083038186803b158015610f0a57600080fd5b505afa158015610f1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f429190615407565b90506000609760009054906101000a90046001600160a01b03166001600160a01b031663ebd2665f6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f9457600080fd5b505afa158015610fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcc9190615304565b6001600160a01b0316630b975991336040518263ffffffff1660e01b8152600401610ff791906154f5565b602060405180830381600087803b15801561101157600080fd5b505af1158015611025573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110499190615407565b90508082101561106b5760405162461bcd60e51b81526004016105809061598b565b7f839237f8da6208af7e49773f22501b3082aaae94d5b6ce8ee96f117835fe2f678360405161109a919061560d565b60405180910390a1610cd184611fb1565b60009081526065602052604090206002015490565b600061054d82612d01565b609854819081106110ee5760405162461bcd60e51b815260040161058090615cc7565b60046110f9836116ba565b600681111561110457fe5b146111215760405162461bcd60e51b81526004016105809061591f565b600061112b612950565b9050336001600160a01b03166098848154811061114457fe5b60009182526020909120600890910201546001600160a01b0316148061128457506040516224441f60e71b81526001600160a01b038216906312220f80906111909033906004016154f5565b60206040518083038186803b1580156111a857600080fd5b505afa1580156111bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e0919061537f565b80156112845750604051630ba7341960e11b81526001600160a01b0382169063174e6832906112139033906004016154f5565b60206040518083038186803b15801561122b57600080fd5b505afa15801561123f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112639190615407565b6098848154811061127057fe5b906000526020600020906008020160010154145b6112a05760405162461bcd60e51b815260040161058090615cfe565b6112f2609884815481106112b057fe5b6000918252602090912060089091020154609880546001600160a01b0390921691869081106112db57fe5b906000526020600020906008020160010154612d3f565b6112fb336118dd565b61130483612e16565b6098848154811061131157fe5b90600052602060002090600802016006018190555061132e612f1d565b6001600160a01b031663568b55b26098858154811061134957fe5b9060005260206000209060080201600601546040518263ffffffff1660e01b8152600401611377919061560d565b60206040518083038186803b15801561138f57600080fd5b505afa1580156113a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c79190615407565b6113da426203f48063ffffffff61261d16565b106113f75760405162461bcd60e51b815260040161058090615db5565b61140083612f62565b7fb0142de902382ce87e0ae1e5ec0699b26d25bec2eeb06bca82e1253099b3119c8360405161142f919061560d565b60405180910390a1505050565b60008281526065602052604090206002015461145a90610446613332565b6114765760405162461bcd60e51b8152600401610580906156cf565b6107d88282613336565b600061148b826133a5565b801561054d57505060a2546001600160a01b0391909116600090815260a360205260409020541090565b6114bd613332565b6001600160a01b0316816001600160a01b0316146114ed5760405162461bcd60e51b815260040161058090615e28565b6107d882826133c2565b60009081526099602052604090205490565b6040805180820182526006815265426f756e747960d01b60208083019190915282518084018452600b81526a2234b9ba3934b13aba37b960a91b918101919091526097549251633581777360e01b815260009333916001600160a01b039091169063358177739061157e90869060040161562a565b60206040518083038186803b15801561159657600080fd5b505afa1580156115aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ce9190615304565b6001600160a01b031614806116695750609754604051633581777360e01b815233916001600160a01b03169063358177739061160e90859060040161562a565b60206040518083038186803b15801561162657600080fd5b505afa15801561163a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165e9190615304565b6001600160a01b0316145b806116775750611677611e4b565b6116935760405162461bcd60e51b815260040161058090615d47565b6000858152609d602052604090206116b1908563ffffffff611e6a16565b95945050505050565b609854600090829081106116e05760405162461bcd60e51b815260040161058090615cc7565b609883815481106116ed57fe5b906000526020600020906008020160050154600014156117f8576098838154811061171457fe5b906000526020600020906008020160060154600014156117ef57611736612f1d565b6001600160a01b031663bf64d8496098858154811061175157fe5b9060005260206000209060080201600401546040518263ffffffff1660e01b815260040161177f919061560d565b60206040518083038186803b15801561179757600080fd5b505afa1580156117ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117cf9190615407565b6117d7612471565b14156117e65760009150610692565b60039150610692565b60029150610692565b6098838154811061180557fe5b90600052602060002090600802016005015461181f612471565b101561182e5760019150610692565b6098838154811061183b57fe5b9060005260206000209060080201600601546000141561185e5760049150610692565b6098838154811061186b57fe5b906000526020600020906008020160060154611885612471565b10156118945760059150610692565b60069150610692565b609a602052816000526040600020818154811061080857fe5b6000828152609c602052604081206118d4908363ffffffff61343116565b90505b92915050565b6118e88160006107c6565b50565b6000806118f6612471565b6001600160a01b038416600090815260a56020526040902060010154909150811115611926576000915050610550565b50506001600160a01b038116600090815260a56020526040902054610550565b6000828152609d602052604081206118d4908363ffffffff6134f116565b60008281526065602052604081206118d4908363ffffffff6135a816565b60008281526065602052604081206118d4908363ffffffff6135b416565b6001600160a01b0391909116600090815260a46020908152604080832093835260019093019052205490565b6203f48081565b609854819081106119f65760405162461bcd60e51b815260040161058090615cc7565b60988281548110611a0357fe5b60009182526020909120600890910201546001600160a01b03163314611a3b5760405162461bcd60e51b81526004016105809061563d565b6000611a46836116ba565b6006811115611a5157fe5b14611a6e5760405162461bcd60e51b815260040161058090615b8d565b611a76612471565b60988381548110611a8357fe5b906000526020600020906008020160060181905550611aea60988381548110611aa857fe5b6000918252602090912060089091020154609880546001600160a01b039092169185908110611ad357fe5b9060005260206000209060080201600201546135c9565b507fc42cff898171c085fa87ecad4869a5fb22753dddf61048199b8c740c2109fb1182604051611b1a919061560d565b60405180910390a15050565b6000818152609d6020526040902060609061054d90613647565b600081565b6097546001600160a01b031681565b60985481908110611b775760405162461bcd60e51b815260040161058090615cc7565b611b7f612950565b6001600160a01b031663bed5012e3360988581548110611b9b57fe5b9060005260206000209060080201600101546040518363ffffffff1660e01b8152600401611bca929190615509565b60206040518083038186803b158015611be257600080fd5b505afa158015611bf6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1a919061537f565b611c365760405162461bcd60e51b815260040161058090615956565b6107d8826137fd565b60988181548110611c4c57fe5b60009182526020918290206008909102018054600180830154600280850154600386015460048701546005880154600689015460078a01805460408051601f6000199c841615610100029c909c0190921698909804998a018d90048d0281018d019097528887526001600160a01b039099169b5095999398929791969095949293830182828015611d1e5780601f10611cf357610100808354040283529160200191611d1e565b820191906000526020600020905b815481529060010190602001808311611d0157829003601f168201915b5050505050905088565b600054610100900460ff1680611d415750611d41613b70565b80611d4f575060005460ff16155b611d6b5760405162461bcd60e51b815260040161058090615afd565b600054610100900460ff16158015611d96576000805460ff1961ff0019909116610100171660011790555b611d9f82613b76565b80156107d8576000805461ff00191690555050565b600081815260656020526040812061054d90613c00565b600082815260656020526040902060020154611de990610446613332565b6114ed5760405162461bcd60e51b8152600401610580906158cf565b6001600160a01b03166000908152609a602052604090205490565b60006118d48383611e2f612471565b613c0b565b600061054d611e42836118eb565b610a0b84612d01565b6000611e578133611982565b90505b90565b606061054d8260006121b1565b6000826003015460001415611e81575060006118d7565b81836003015411611f9a5760038301545b828111611f825760008181526001808601602090815260408084205491889052832054611eff92611ef3919060028a01908690611ed690899063ffffffff6125db16565b81526020019081526020016000205461261d90919063ffffffff16565b9063ffffffff613c4616565b60008381526002870160205260409020549091508114611f2d57600082815260028601602052604090208190555b60008281526020869052604090205415611f51576000828152602086905260408120555b600082815260018601602052604090205415611f795760008281526001860160205260408120555b50600101611e92565b50611f9482600163ffffffff61261d16565b60038401555b506000908152600291909101602052604090205490565b60975460408051636f72c4ab60e01b815290516000926001600160a01b031691636f72c4ab916004808301926020929190829003018186803b158015611ff657600080fd5b505afa15801561200a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202e9190615304565b9050600080805b845181101561214357826001600160a01b031685828151811061205457fe5b6020026020010151600001516001600160a01b03161461210e5781156120d557604051634458328b60e01b81526001600160a01b03851690634458328b906120a29086908690600401615509565b600060405180830381600087803b1580156120bc57600080fd5b505af11580156120d0573d6000803e3d6000fd5b505050505b8481815181106120e157fe5b60200260200101516000015192508481815181106120fb57fe5b602002602001015160200151915061213b565b61213885828151811061211d57fe5b6020026020010151602001518361261d90919063ffffffff16565b91505b600101612035565b5080156121ab57604051634458328b60e01b81526001600160a01b03841690634458328b906121789085908590600401615509565b600060405180830381600087803b15801561219257600080fd5b505af11580156121a6573d6000803e3d6000fd5b505050505b50505050565b60606121bc83611480565b156118d7576001600160a01b038316600090815260a3602052604090205460a25483158015906121fa5750806121f8838663ffffffff61261d16565b105b156122125761220f828563ffffffff61261d16565b90505b612222818363ffffffff6125db16565b67ffffffffffffffff8111801561223857600080fd5b5060405190808252806020026020018201604052801561227257816020015b61225f615239565b8152602001906001900390816122575790505b509250815b8183101561245057600060a2848154811061228e57fe5b9060005260206000209060040201600201549050600060a285815481106122b157fe5b906000526020600020906004020160030154905060006122d2898484613c0b565b90506122e581600063ffffffff613c9916565b15612442576001600160a01b0389166000908152609f6020526040902060a280546123679291908990811061231657fe5b6000918252602080832060408051808201825260049094029091018054845260010154838301526001600160a01b038f16845260a0825280842089855290915290912091908563ffffffff613cb216565b6123c760a2878154811061237757fe5b6000918252602080832060408051808201825260049094029091018054845260010154838301526001600160a01b038e16845260a18252808420888552909152909120908463ffffffff61264216565b88876123d9888763ffffffff6125db16565b815181106123e357fe5b60209081029190910101516001600160a01b0390911690526124166124098a8585613c0b565b829063ffffffff613c4616565b87612427888763ffffffff6125db16565b8151811061243157fe5b602002602001015160200181815250505b505050826001019250612277565b506001600160a01b038516600090815260a360205260409020555092915050565b600061247b612f1d565b6001600160a01b031663ddd1b67e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156124b357600080fd5b505afa1580156124c7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e579190615407565b6000828152609c602052604081206118d4908363ffffffff613cc016565b61251161521f565b600384015461252783600163ffffffff61261d16565b10156125455760405162461bcd60e51b81526004016105809061571e565b600384015461255f576125586000613de3565b90506125d4565b600061256b8584613cc0565b905061257e81600063ffffffff613df616565b156125955761258d6000613de3565b9150506125d4565b83808210156125a15750805b6125a961521f565b6125c26125bc848463ffffffff613c4616565b84613e1c565b90506125cf878287613e6c565b925050505b9392505050565b60006118d483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613e7a565b6000828201838110156118d45760405162461bcd60e51b8152600401610580906157e4565b600383015461265882600163ffffffff61261d16565b10156126765760405162461bcd60e51b81526004016105809061571e565b60208201518251111561269b5760405162461bcd60e51b815260040161058090615755565b60038301546126a95761278d565b60006126b58483611e6a565b90506126c881600063ffffffff613df616565b156126d3575061278d565b602080840151845160008581526002880190935260409092205461270d92612701919063ffffffff613ea616565b9063ffffffff613ee016565b600083815260028601602052604081209190915561273283600163ffffffff61261d16565b90505b8460040154811161278a57602080850151855160008481526001890190935260409092205461276e92612701919063ffffffff613ea616565b6000828152600180880160205260409091209190915501612735565b50505b505050565b60018301546127d05760018084018290556002808501839055600083815260208681526040822086518155908601519381019390935591015561278d565b80836002015411156127f45760405162461bcd60e51b815260040161058090615ab8565b808360020154141561285557600081815260208481526040918290208251808401909352805483526001015490820152612834908363ffffffff613f2216565b6000828152602085815260409091208251815591015160019091015561278d565b60008181526020848152604080832085518155918501516001830155600291820183905581860180548452922001829055819055505050565b6097546040805163f49bff7b60e01b815290516000926001600160a01b03169163f49bff7b916004808301926020929190829003018186803b1580156128d357600080fd5b505afa1580156128e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e579190615304565b609754604080516323f9e0d960e11b815290516000926001600160a01b0316916347f3c1b2916004808301926020929190829003018186803b1580156128d357600080fd5b60975460408051639cb83f5760e01b815290516000926001600160a01b031691639cb83f57916004808301926020929190829003018186803b1580156128d357600080fd5b6001600160a01b038216600090815260a660209081526040808320848452600101909152812054151580612a8657506001600160a01b038316600090815260a660209081526040808320858452600101909152902054158015612a8657506129fb613f60565b6001600160a01b031663049e41776040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3357600080fd5b505afa158015612a47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6b9190615407565b6001600160a01b038416600090815260a66020526040902054105b6118d75760405162461bcd60e51b815260040161058090615d7e565b6098805460408051610100810182526001600160a01b03898116825260208083018a8152938301898152606084018981524260808601908152600060a0870181815260c0880182815260e089018d815260018c018d559b90925287517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81460088c0290810180546001600160a01b0319169290991691909117885598517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d8158a015593517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81689015591517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d817880155517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81887015590517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d819860155517f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81a85015594518051949592949193612c59937f2237a976fa961f5921fd19f2b03c925c725d77b20ce8f790c19709c03de4d81b90910192910190615250565b5050506000858152609960209081526040808320805460018181018355918552838520018590556001600160a01b038a168452609a835290832080549182018155835291200181905560988054612cf7919083908110612cb557fe5b6000918252602090912060089091020154609880546001600160a01b039092169184908110612ce057fe5b906000526020600020906008020160020154613fa5565b5095945050505050565b600080612d0c612471565b9050612d17836118dd565b6001600160a01b0383166000908152609f602052604090206125d4908263ffffffff613cc016565b6001600160a01b038216600090815260a6602090815260408083208484526001908101909252909120541415612db3576001600160a01b038216600090815260a66020526040902054612d9990600163ffffffff6125db16565b6001600160a01b038316600090815260a660205260409020555b6001600160a01b038216600090815260a660209081526040808320848452600190810190925290912054612dec9163ffffffff6125db16565b6001600160a01b03909216600090815260a660209081526040808320938352600190930190522055565b600080612e21612471565b9050600060988481548110612e3257fe5b906000526020600020906008020160050154905080821015612e8857612e7f60988581548110612e5e57fe5b9060005260206000209060080201600301548261261d90919063ffffffff16565b92505050610550565b6000612ebf60988681548110612e9a57fe5b90600052602060002090600802016003015461270184866125db90919063ffffffff16565b9050612f13612f0660988781548110612ed457fe5b906000526020600020906008020160030154612efa60018561261d90919063ffffffff16565b9063ffffffff613ea616565b839063ffffffff61261d16565b9350505050610550565b6097546040805163954b385d60e01b815290516000926001600160a01b03169163954b385d916004808301926020929190829003018186803b1580156128d357600080fd5b6000612f6d82614050565b9050612fb660988381548110612f7f57fe5b9060005260206000209060080201600101548260988581548110612f9f57fe5b906000526020600020906008020160060154614189565b61301060988381548110612fc657fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b03168260988581548110612ff957fe5b9060005260206000209060080201600601546141a8565b6130826098838154811061302057fe5b6000918252602090912060089091020154609880546001600160a01b03909216918590811061304b57fe5b906000526020600020906008020160010154836098868154811061306b57fe5b9060005260206000209060080201600601546141d1565b600061313561308f61290b565b6001600160a01b031663f5b98f41609886815481106130aa57fe5b9060005260206000209060080201600301546040518263ffffffff1660e01b81526004016130d8919061560d565b60206040518083038186803b1580156130f057600080fd5b505afa158015613104573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131289190615407565b839063ffffffff613ea616565b905061317e6098848154811061314757fe5b906000526020600020906008020160010154826098868154811061316757fe5b906000526020600020906008020160060154614205565b6131f06098848154811061318e57fe5b6000918252602090912060089091020154609880546001600160a01b0390921691869081106131b957fe5b90600052602060002090600802016001015483609887815481106131d957fe5b906000526020600020906008020160060154614224565b6131f8614258565b6001600160a01b0316630d4e8fd16098858154811061321357fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b0316856098878154811061324657fe5b9060005260206000209060080201600601546040518463ffffffff1660e01b815260040161327693929190615522565b600060405180830381600087803b15801561329057600080fd5b505af11580156132a4573d6000803e3d6000fd5b505050506132b061288e565b6001600160a01b0316635a4adb6882609886815481106132cc57fe5b9060005260206000209060080201600601546040518363ffffffff1660e01b81526004016132fb929190615ee4565b600060405180830381600087803b15801561331557600080fd5b505af1158015613329573d6000803e3d6000fd5b50505050505050565b3390565b6000828152606560205260409020613354908263ffffffff61429d16565b156107d857613361613332565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b0316600090815260a46020526040902054151590565b60008281526065602052604090206133e0908263ffffffff6142b216565b156107d8576133ed613332565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b600382015460009061344a83600163ffffffff61261d16565b10156134685760405162461bcd60e51b81526004016105809061584b565b6003830154613479575060006118d7565b818360030154116134e657600283015460038401545b8381116134de57600081815260018601602090815260408083205491889052909120546134d491906134c890859063ffffffff61261d16565b9063ffffffff6125db16565b915060010161348f565b5090506118d7565b5060028201546118d7565b6000826003015460001415613508575060006118d7565b81836003015411613591576000836002016000613533600187600301546125db90919063ffffffff16565b81526020019081526020016000205490506000846003015490505b8381116134de576000818152600186016020908152604080832054918890529091205461358791906134c890859063ffffffff61261d16565b915060010161354e565b5060008181526002830160205260409020546118d7565b60006118d483836142c7565b60006118d4836001600160a01b03841661430c565b6000806135d4612471565b6001600160a01b038516600090815260a5602052604090206001015490915081146135fb57fe5b6001600160a01b038416600090815260a56020526040902054613624908463ffffffff6125db16565b6001600160a01b03909416600090815260a5602052604090209390935592915050565b606081600301546000141561365b57610550565b600382015460009061367490600163ffffffff6125db16565b905060006136906001856004015461261d90919063ffffffff16565b90508181116136ad576136aa82600163ffffffff61261d16565b90505b6136bd818363ffffffff6125db16565b67ffffffffffffffff811180156136d357600080fd5b506040519080825280602002602001820160405280156136fd578160200160208202803683370190505b50925083600201600061371e600187600301546125db90919063ffffffff16565b8152602001908152602001600020548360008151811061373a57fe5b602090810291909101015260005b835161375b82600163ffffffff61261d16565b10156137f5576003850154600090613779908363ffffffff61261d16565b6000818152600188016020908152604080832054918a90529091205487519293506137c5926134c891908990879081106137af57fe5b602002602001015161261d90919063ffffffff16565b856137d784600163ffffffff61261d16565b815181106137e157fe5b602090810291909101015250600101613748565b505050919050565b61384f6098828154811061380d57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918490811061383857fe5b906000526020600020906008020160010154612995565b50600061385b826116ba565b9050600081600681111561386b57fe5b1461393657600181600681111561387e57fe5b14806138955750600481600681111561389357fe5b145b806138ab575060058160068111156138a957fe5b145b806138c1575060068160068111156138bf57fe5b145b156138de5760405162461bcd60e51b81526004016105809061579c565b60028160068111156138ec57fe5b141561390a5760405162461bcd60e51b815260040161058090615c76565b600381600681111561391857fe5b14156139365760405162461bcd60e51b81526004016105809061588d565b600081600681111561394457fe5b146139615760405162461bcd60e51b815260040161058090615bea565b60606139926098848154811061397357fe5b60009182526020909120600890910201546001600160a01b0316611e5d565b905061399d83614324565b6000609884815481106139ac57fe5b90600052602060002090600802016002015490506139c8614258565b6001600160a01b03166394df393f609886815481106139e357fe5b906000526020600020906008020160000160009054906101000a90046001600160a01b0316868460988981548110613a1757fe5b9060005260206000209060080201600501546040518563ffffffff1660e01b8152600401613a489493929190615543565b600060405180830381600087803b158015613a6257600080fd5b505af1158015613a76573d6000803e3d6000fd5b505050506000613aa2613a8761290b565b6001600160a01b031663f5b98f41609888815481106130aa57fe5b9050613aac61288e565b6001600160a01b0316636ad5a9cf8260988881548110613ac857fe5b9060005260206000209060080201600501546040518363ffffffff1660e01b8152600401613af7929190615ee4565b600060405180830381600087803b158015613b1157600080fd5b505af1158015613b25573d6000803e3d6000fd5b50505050613b3283611fb1565b7fdb0c41de0e1a6e61f3ea29d9618edd8bfe8cb4e041a267c54eec70418341272d85604051613b61919061560d565b60405180910390a15050505050565b303b1590565b600054610100900460ff1680613b8f5750613b8f613b70565b80613b9d575060005460ff16155b613bb95760405162461bcd60e51b815260040161058090615afd565b600054610100900460ff16158015613be4576000805460ff1961ff0019909116610100171660011790555b613bec61475c565b613bf7600033611476565b611d9f826147ee565b600061054d82614864565b6001600160a01b038316600090815260a0602090815260408083208584529091528120613c3e908363ffffffff613cc016565b949350505050565b6000818310613c5857508082036118d7565b7f5b70a077a991facb623c7b2ee44cc539dc6ba345b6636552b8ea97fbbd4d54198383604051613c89929190615ee4565b60405180910390a15060006118d7565b6000620f4240198210613ca857fe5b50620f4240011090565b6121ab848484846001614868565b6003820154600090613cd983600163ffffffff61261d16565b1015613cf75760405162461bcd60e51b81526004016105809061584b565b6003830154613d08575060006118d7565b81836003015411613dda57600283015460038401545b838111613dae5760008181526001860160209081526040808320549188905290912054613d579190611ef390859063ffffffff61261d16565b60008281526020879052604090205490925015613d7e576000818152602086905260408120555b600081815260018601602052604090205415613da65760008181526001860160205260408120555b600101613d1e565b5080846002015414613dc257600284018190555b613dd383600163ffffffff61261d16565b6003850155505b50506002015490565b613deb61521f565b61054d826001613e1c565b600081831115613e0e5750620f4240818303106118d7565b50620f4240828203106118d7565b613e2461521f565b60008211613e445760405162461bcd60e51b815260040161058090615a57565b613e4c61521f565b60405180604001604052808581526020018481525090506118d481614a4f565b61278d838484846000614868565b60008184841115613e9e5760405162461bcd60e51b8152600401610580919061562a565b505050900390565b600082613eb5575060006118d7565b82820282848281613ec257fe5b04146118d45760405162461bcd60e51b8152600401610580906159df565b60006118d483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614a9b565b613f2a61521f565b815183516118d491613f42919063ffffffff613ea616565b60208085015190860151613f5b9163ffffffff613ea616565b613e1c565b60975460408051633f2a95e960e21b815290516000926001600160a01b03169163fcaa57a4916004808301926020929190829003018186803b1580156128d357600080fd5b600080613fb0612471565b6001600160a01b038516600090815260a56020526040902060010154909150811115613ffc576001600160a01b038416600090815260a560205260409020838155600101819055614049565b6001600160a01b038416600090815260a56020526040902060010154811461402057fe5b6001600160a01b038416600090815260a56020526040902054613624908463ffffffff61261d16565b5092915050565b6000818152609b6020526040812054609880548391908590811061407057fe5b906000526020600020906008020160010154905060006098858154811061409357fe5b906000526020600020906008020160020154905082600014156140d3576000828152609e60205260409020600101549250826140d3579250610550915050565b825b6000811180156141025750609886815481106140ed57fe5b90600052602060002090600802016006015481105b15614180576098868154811061411457fe5b906000526020600020906008020160050154811061415f576000838152609e6020908152604080832084845290915290206001810154905461415c9190612701908590613ea6565b91505b6000838152609e6020908152604080832093835292905220600201546140d5565b50949350505050565b6000838152609c6020526040902061278d90838363ffffffff614ad216565b6001600160a01b0383166000908152609f6020526040902061278d90838363ffffffff614ad216565b6001600160a01b038416600090815260a06020908152604080832086845290915290206121ab90838363ffffffff614ad216565b6000838152609d6020526040902061278d90838363ffffffff614b9316565b6001600160a01b038416600090815260a16020908152604080832086845290915290206121ab90838363ffffffff614b9316565b6097546040805163541a252760e01b815290516000926001600160a01b03169163541a2527916004808301926020929190829003018186803b1580156128d357600080fd5b60006118d4836001600160a01b038416614c11565b60006118d4836001600160a01b038416614c5b565b815460009082106142ea5760405162461bcd60e51b81526004016105809061568d565b8260000182815481106142f957fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b600061432e612471565b905061434181600163ffffffff61261d16565b6098838154811061434e57fe5b9060005260206000209060080201600501819055506000609e60006098858154811061437657fe5b90600052602060002090600802016001015481526020019081526020016000206002015411156143e757609e6000609884815481106143b157fe5b60009182526020808320600160089093020191909101548352828101939093526040918201812060020154858252609b90935220555b614441609883815481106143f757fe5b9060005260206000209060080201600101546098848154811061441657fe5b90600052602060002090600802016002015461443c60018561261d90919063ffffffff16565b614d21565b6144a76098838154811061445157fe5b6000918252602090912060089091020154609880546001600160a01b03909216918590811061447c57fe5b9060005260206000209060080201600201546144a260018561261d90919063ffffffff16565b614d40565b61452c609883815481106144b757fe5b6000918252602090912060089091020154609880546001600160a01b0390921691859081106144e257fe5b9060005260206000209060080201600101546098858154811061450157fe5b90600052602060002090600802016002015461452760018661261d90919063ffffffff16565b614d69565b6145926098838154811061453c57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918590811061456757fe5b90600052602060002090600802016001015461458d60018561261d90919063ffffffff16565b614d9d565b600061466561459f61290b565b6001600160a01b031663f5b98f41609886815481106145ba57fe5b9060005260206000209060080201600301546040518263ffffffff1660e01b81526004016145e8919061560d565b60206040518083038186803b15801561460057600080fd5b505afa158015614614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146389190615407565b6098858154811061464557fe5b906000526020600020906008020160020154613ea690919063ffffffff16565b90506146a36098848154811061467757fe5b9060005260206000209060080201600101548261469e60018661261d90919063ffffffff16565b614e3b565b61470a609884815481106146b357fe5b6000918252602090912060089091020154609880546001600160a01b0390921691869081106146de57fe5b9060005260206000209060080201600101548361470560018761261d90919063ffffffff16565b614e5a565b61278d6098848154811061471a57fe5b6000918252602090912060089091020154609880546001600160a01b03909216918690811061474557fe5b906000526020600020906008020160010154614e8e565b600054610100900460ff16806147755750614775613b70565b80614783575060005460ff16155b61479f5760405162461bcd60e51b815260040161058090615afd565b600054610100900460ff161580156147ca576000805460ff1961ff0019909116610100171660011790555b6147d2614f36565b6147da614f36565b80156118e8576000805461ff001916905550565b6001600160a01b0381166148145760405162461bcd60e51b815260040161058090615b4b565b614826816001600160a01b0316614fb7565b6148425760405162461bcd60e51b815260040161058090615a20565b609780546001600160a01b0319166001600160a01b0392909216919091179055565b5490565b600385015461487e83600163ffffffff61261d16565b101561489c5760405162461bcd60e51b81526004016105809061571e565b80156148d65760038401546148b883600163ffffffff61261d16565b10156148d65760405162461bcd60e51b81526004016105809061571e565b6020830151835111156148fb5760405162461bcd60e51b815260040161058090615755565b60038501546149095761278a565b60006149158684613cc0565b905061492881600063ffffffff613df616565b15614933575061278a565b6000614958856020015161270187600001518a60020154613ea690919063ffffffff16565b90508215614981576149818661497b838a60020154613c4690919063ffffffff16565b86614ad2565b60028701819055600061499b85600163ffffffff61261d16565b90505b876004015481116121a6576020808701518751600084815260018c0190935260408320546149d79291612701919063ffffffff613ea616565b90508415614a3357600082815260018a016020526040902054614a2190614a04908363ffffffff613c4616565b600084815260018b0160205260409020549063ffffffff613c4616565b600083815260018a0160205260409020555b60008281526001808b016020526040909120919091550161499e565b6000614a6382600001518360200151614ff0565b8251909150614a78908263ffffffff613ee016565b82526020820151614a8f908263ffffffff613ee016565b60209092019190915250565b60008183614abc5760405162461bcd60e51b8152600401610580919061562a565b506000838581614ac857fe5b0495945050505050565b614ae381600163ffffffff61261d16565b83600301541115614b065760405162461bcd60e51b815260040161058090615a81565b6003830154614b1e5760038301819055600483018190555b8260040154811115614b3257600483018190555b82600301548110614b74576000818152600184016020526040902054614b5e908363ffffffff61261d16565b600082815260018501602052604090205561278d565b6002830154614b89908363ffffffff613c4616565b6002840155505050565b8083600301541115614bb75760405162461bcd60e51b815260040161058090615a81565b6003830154614bc857600383018190555b6000818152600184016020526040902054614be9908363ffffffff61261d16565b60008281526001850160205260409020556004830154811461278d5760048301819055505050565b6000614c1d838361430c565b614c53575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556118d7565b5060006118d7565b60008181526001830160205260408120548015614d175783546000198083019190810190600090879083908110614c8e57fe5b9060005260206000200154905080876000018481548110614cab57fe5b600091825260208083209091019290925582815260018981019092526040902090840190558654879080614cdb57fe5b600190038181906000526020600020016000905590558660010160008781526020019081526020016000206000905560019450505050506118d7565b60009150506118d7565b6000838152609c6020526040902061278d90838363ffffffff61504016565b6001600160a01b0383166000908152609f6020526040902061278d90838363ffffffff61504016565b6001600160a01b038416600090815260a06020908152604080832086845290915290206121ab90838363ffffffff61504016565b6001600160a01b038316600090815260a46020526040902054614de5576001600160a01b038316600090815260a46020908152604080832084905560a25460a3909252909120555b6001600160a01b038316600090815260a46020908152604080832085845260010190915290205461278d576001600160a01b0392909216600090815260a460209081526040808320938352600190930190522055565b6000838152609d6020526040902061278d90838363ffffffff6150e316565b6001600160a01b038416600090815260a16020908152604080832086845290915290206121ab90838363ffffffff6150e316565b6001600160a01b038216600090815260a660209081526040808320848452600101909152902054614efd576001600160a01b038216600090815260a66020526040902054614ee390600163ffffffff61261d16565b6001600160a01b038316600090815260a660205260409020555b6001600160a01b038216600090815260a660209081526040808320848452600190810190925290912054612dec9163ffffffff61261d16565b600054610100900460ff1680614f4f5750614f4f613b70565b80614f5d575060005460ff16155b614f795760405162461bcd60e51b815260040161058090615afd565b600054610100900460ff161580156147da576000805460ff1961ff00199091166101001716600117905580156118e8576000805461ff001916905550565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590613c3e575050151592915050565b600082828181111561500c57615006828261515d565b90925090505b801561503857615022828263ffffffff61516016565b915061502e828261515d565b909250905061500c565b509392505050565b80836003015411156150645760405162461bcd60e51b81526004016105809061581b565b600383015461507c5760038301819055600483018190555b826004015481111561509057600483018190555b826003015481106150ce576000818152602084905260409020546150ba908363ffffffff61261d16565b60008281526020859052604090205561278d565b6002830154614b89908363ffffffff61261d16565b80836003015411156151075760405162461bcd60e51b81526004016105809061581b565b600383015461511857600383018190555b600081815260208490526040902054615137908363ffffffff61261d16565b6000828152602085905260409020556004830154811461278d5760048301819055505050565b91565b60006118d483836040518060400160405280601881526020017f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000815250600081836151be5760405162461bcd60e51b8152600401610580919061562a565b508284816151c857fe5b06949350505050565b60405180610100016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081525090565b604051806040016040528060008152602001600081525090565b604080518082019091526000808252602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061529157805160ff19168380011785556152be565b828001600101855582156152be579182015b828111156152be5782518255916020019190600101906152a3565b506152ca9291506152ce565b5090565b611e5a91905b808211156152ca57600081556001016152d4565b6000602082840312156152f9578081fd5b81356118d481615ef2565b600060208284031215615315578081fd5b81516118d481615ef2565b60008060408385031215615332578081fd5b823561533d81615ef2565b946020939093013593505050565b60008060006060848603121561535f578081fd5b833561536a81615ef2565b95602085013595506040909401359392505050565b600060208284031215615390578081fd5b815180151581146118d4578182fd5b6000602082840312156153b0578081fd5b5035919050565b600080604083850312156153c9578182fd5b8235915060208301356153db81615ef2565b809150509250929050565b600080604083850312156153f8578182fd5b50508035926020909101359150565b600060208284031215615418578081fd5b5051919050565b600080600080600060808688031215615436578081fd5b853594506020860135935060408601359250606086013567ffffffffffffffff80821115615462578283fd5b81880189601f820112615473578384fd5b8035925081831115615483578384fd5b896020848301011115615494578384fd5b6020810194505050809150509295509295909350565b60008151808452815b818110156154cf576020818501810151868301820152016154b3565b818111156154e05782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b600061010060018060a01b038b1683528960208401528860408401528760608401528660808401528560a08401528460c08401528060e08401526155af818401856154aa565b9b9a5050505050505050505050565b6020808252825182820181905260009190848201906040850190845b818110156155f6578351835292840192918401916001016155da565b50909695505050505050565b901515815260200190565b90815260200190565b602081016007831061562457fe5b91905290565b6000602082526118d460208301846154aa565b60208082526030908201527f4f6e6c7920746f6b656e20686f6c646572732063616e2063616e63656c20646560408201526f1b1959d85d1a5bdb881c995c5d595cdd60821b606082015260800190565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252602f908201527f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60408201526e0818591b5a5b881d1bc819dc985b9d608a1b606082015260800190565b6020808252601f908201527f43616e6e6f74207265647563652076616c756520696e20746865207061737400604082015260600190565b60208082526027908201527f496e6372656173696e67206f662076616c756573206973206e6f7420696d706c604082015266195b595b9d195960ca1b606082015260800190565b60208082526028908201527f5468652064656c65676174696f6e20686173206265656e20616c7265616479206040820152671858d8d95c1d195960c21b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526016908201527510d85b9b9bdd08185919081d1bc81d1a19481c185cdd60521b604082015260600190565b60208082526022908201527f43616e6e6f742063616c63756c6174652076616c756520696e207468652070616040820152611cdd60f21b606082015260800190565b60208082526022908201527f5468652064656c65676174696f6e2072657175657374206973206f7574646174604082015261195960f21b606082015260800190565b60208082526030908201527f416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e60408201526f2061646d696e20746f207265766f6b6560801b606082015260800190565b6020808252601b908201527f43616e6e6f74207265717565737420756e64656c65676174696f6e0000000000604082015260600190565b6020808252818101527f4e6f207065726d697373696f6e7320746f206163636570742072657175657374604082015260600190565b60208082526034908201527f546f6b656e20686f6c64657220646f6573206e6f74206861766520656e6f75676040820152736820746f6b656e7320746f2064656c656761746560601b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527f41646472657373206973206e6f7420636f6e7472616374000000000000000000604082015260600190565b60208082526010908201526f4469766973696f6e206279207a65726f60801b604082015260600190565b6020808252601d908201527f43616e6e6f742073756274726163742066726f6d207468652070617374000000604082015260600190565b60208082526025908201527f43616e6e6f742070757420736c617368696e67206576656e7420696e20746865604082015264081c185cdd60da1b606082015260800190565b6020808252602e908201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560408201526d195b881a5b9a5d1a585b1a5e995960921b606082015260800190565b60208082526022908201527f436f6e74726163744d616e616765722061646472657373206973206e6f742073604082015261195d60f21b606082015260800190565b6020808252603a908201527f546f6b656e20686f6c6465727320617265206f6e6c792061626c6520746f206360408201527f616e63656c2050524f504f5345442064656c65676174696f6e73000000000000606082015260800190565b60208082526027908201527f43616e6e6f74207365742064656c65676174696f6e20737461746520746f206160408201526618d8d95c1d195960ca1b606082015260800190565b60208082526025908201527f546869732064656c65676174696f6e20706572696f64206973206e6f7420616c6040820152641b1bddd95960da1b606082015260800190565b60208082526031908201527f5468652064656c65676174696f6e20686173206265656e2063616e63656c6c656040820152703210313c903a37b5b2b7103437b63232b960791b606082015260800190565b60208082526019908201527f44656c65676174696f6e20646f6573206e6f7420657869737400000000000000604082015260600190565b60208082526029908201527f5065726d697373696f6e2064656e69656420746f207265717565737420756e6460408201526832b632b3b0ba34b7b760b91b606082015260800190565b60208082526019908201527f4d6573736167652073656e64657220697320696e76616c696400000000000000604082015260600190565b6020808252601e908201527f4c696d6974206f662076616c696461746f727320697320726561636865640000604082015260600190565b6020808252604d908201527f556e64656c65676174696f6e207265717565737473206d75737420626520736560408201527f6e7420332064617973206265666f72652074686520656e64206f662064656c6560608201526c19d85d1a5bdb881c195c9a5bd9609a1b608082015260a00190565b6020808252602f908201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560408201526e103937b632b9903337b91039b2b63360891b606082015260800190565b60006020825260018060a01b038351166020830152602083015160408301526040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e0830151610100808185015250613c3e6101208401826154aa565b918252602082015260400190565b6001600160a01b03811681146118e857600080fdfea26469706673582212202b07a6c506eb6d89666a5ba1fd6c0c95af96f1573f9b9d64ae12b450d671511964736f6c634300060a0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.