// 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/>.
*/pragmasolidity 0.6.10;import"./Permissions.sol";
/**
* @title Contains constants and common variables for Skale Manager system
* @author Artem Payvin
*/contractConstantsHolderisPermissions{
// initial price for creating Node (100 SKL)uintpublicconstant NODE_DEPOSIT =100*1e18;
uint8publicconstant TOTAL_SPACE_ON_NODE =128;
// part of Node for Small Skale-chain (1/128 of Node)uint8publicconstant SMALL_DIVISOR =128;
// part of Node for Medium Skale-chain (1/8 of Node)uint8publicconstant MEDIUM_DIVISOR =8;
// part of Node for Large Skale-chain (full Node)uint8publicconstant LARGE_DIVISOR =1;
// part of Node for Medium Test Skale-chain (1/4 of Node)uint8publicconstant MEDIUM_TEST_DIVISOR =4;
// typically number of Nodes for Skale-chain (16 Nodes)uintpublicconstant NUMBER_OF_NODES_FOR_SCHAIN =16;
// number of Nodes for Test Skale-chain (2 Nodes)uintpublicconstant NUMBER_OF_NODES_FOR_TEST_SCHAIN =2;
// number of Nodes for Test Skale-chain (4 Nodes)uintpublicconstant NUMBER_OF_NODES_FOR_MEDIUM_TEST_SCHAIN =4;
// number of seconds in one yearuint32publicconstant SECONDS_TO_YEAR =31622400;
// initial number of monitorsuintpublicconstant NUMBER_OF_MONITORS =24;
uintpublicconstant OPTIMAL_LOAD_PERCENTAGE =80;
uintpublicconstant ADJUSTMENT_SPEED =1000;
uintpublicconstant COOLDOWN_TIME =60;
uintpublicconstant MIN_PRICE =10**6;
uintpublicconstant MSR_REDUCING_COEFFICIENT =2;
uintpublicconstant DOWNTIME_THRESHOLD_PART =30;
uintpublicconstant BOUNTY_LOCKUP_MONTHS =3;
// MSR - Minimum staking requirementuintpublic msr;
// Reward period - 30 days (each 30 days Node would be granted for bounty)uint32public rewardPeriod;
// Allowable latency - 150000 ms by defaultuint32public 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)
*/uint32public deltaPeriod;
/**
* Check time - 2 minutes (every 2 minutes monitors should check metrics
* from checked nodes)
*/uintpublic checkTime;
//Need to add minimal allowed parameters for verdictsuintpublic launchTimestamp;
uintpublic rotationDelay;
uintpublic proofOfUseLockUpPeriodDays;
uintpublic proofOfUseDelegationPercentage;
/**
* Set reward and delta periods to new one, run only by owner. This function
* only for tests.
* @param newRewardPeriod - new Reward period
* @param newDeltaPeriod - new Delta period
*/functionsetPeriods(uint32 newRewardPeriod, uint32 newDeltaPeriod) externalonlyOwner{
require(
newRewardPeriod >= newDeltaPeriod && newRewardPeriod - newDeltaPeriod >= checkTime,
"Incorrect Periods"
);
rewardPeriod = newRewardPeriod;
deltaPeriod = newDeltaPeriod;
}
/**
* Set new check time. This function only for tests.
* @param newCheckTime - new check time
*/functionsetCheckTime(uint newCheckTime) externalonlyOwner{
require(rewardPeriod - deltaPeriod >= checkTime, "Incorrect check time");
checkTime = newCheckTime;
}
/**
* Set latency new one in ms, run only by owner. This function
* only for tests.
* @param newAllowableLatency - new Allowable Latency
*/functionsetLatency(uint32 newAllowableLatency) externalonlyOwner{
allowableLatency = newAllowableLatency;
}
functionsetMSR(uint newMSR) externalonlyOwner{
msr = newMSR;
}
functionsetLaunchTimestamp(uint timestamp) externalonlyOwner{
require(now< launchTimestamp, "Can't set network launch timestamp because network is already launched");
launchTimestamp = timestamp;
}
functionsetRotationDelay(uint newDelay) externalonlyOwner{
rotationDelay = newDelay;
}
functionsetProofOfUseLockUpPeriod(uint periodDays) externalonlyOwner{
proofOfUseLockUpPeriodDays = periodDays;
}
functionsetProofOfUseDelegationPercentage(uint percentage) externalonlyOwner{
require(percentage <=100, "Percentage value is incorrect");
proofOfUseDelegationPercentage = percentage;
}
/**
* @dev constructor in Permissions approach
* @param contractsAddress needed in Permissions constructor
*/functioninitialize(address contractsAddress) publicoverrideinitializer{
Permissions.initialize(contractsAddress);
msr =0;
rewardPeriod =86400;
allowableLatency =150000;
deltaPeriod =3600;
checkTime =300;
launchTimestamp =uint(-1);
rotationDelay =12hours;
proofOfUseLockUpPeriodDays =90;
proofOfUseDelegationPercentage =50;
}
}
Contract Source Code
File 3 of 36: ContractManager.sol
// 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/>.
*/pragmasolidity 0.6.10;import"./OEPOwnable.sol";
import"./OEPAddress.sol";
import"./StringUtils.sol";
/**
* @title Main contract in upgradeable approach. This contract contains the actual
* current mapping from contract IDs (in the form of human-readable strings) to addresses.
* @author Artem Payvin
*/contractContractManagerisOwnableUpgradeSafe{
usingStringUtilsforstring;
usingAddressforaddress;
// mapping of actual smart contracts addressesmapping (bytes32=>address) public contracts;
eventContractUpgraded(string contractsName, address contractsAddress);
functioninitialize() externalinitializer{
OwnableUpgradeSafe.__Ownable_init();
}
/**
* Adds actual contract to mapping of actual contract addresses
* @param contractsName - contracts name in skale manager system
* @param newContractsAddress - contracts address in skale manager system
*/functionsetContractsAddress(stringcalldata contractsName, address newContractsAddress) externalonlyOwner{
// check newContractsAddress is not equal to zerorequire(newContractsAddress !=address(0), "New address is equal zero");
// create hash of contractsNamebytes32 contractId =keccak256(abi.encodePacked(contractsName));
// check newContractsAddress is not equal the previous contract's addressrequire(contracts[contractId] != newContractsAddress, "Contract is already added");
require(newContractsAddress.isContract(), "Given contracts address does not contain code");
// add newContractsAddress to mapping of actual contract addresses
contracts[contractId] = newContractsAddress;
emit ContractUpgraded(contractsName, newContractsAddress);
}
functiongetContract(stringcalldata name) externalviewreturns (address contractAddress) {
contractAddress = contracts[keccak256(abi.encodePacked(name))];
require(contractAddress !=address(0), name.strConcat(" contract has not been found"));
}
}
Contract Source Code
File 4 of 36: DelegationController.sol
// 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/>.
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;import"./OCSafeMath.sol";
import"./Permissions.sol";
import"./SkaleToken.sol";
import"./Nodes.sol";
import"./MathUtils.sol";
import"./FractionUtils.sol";
import"./DelegationPeriodManager.sol";
import"./Punisher.sol";
import"./TokenLaunchLocker.sol";
import"./TokenState.sol";
import"./ValidatorService.sol";
import"./PartialDifferences.sol";
/**
* @title Delegation Controller
* @dev This contract performs all delegation functions including delegation
* requests, undelegation, slashing, etc.
*
* Delegators and validators may both perform delegations. Validators who perform
* delegations to themselves are effectively self-delegating or self-bonding.
*
* Delegated tokens may be in one of several states:
*
* - PROPOSED: token holder proposes tokens to delegate to a validator
* - ACCEPTED: token delegations are accepted by a validator and are locked-by-delegation
* - CANCELED: token holder cancels delegation proposal. Only allowed before the proposal is accepted by the validator
* - REJECTED: token proposal expires at the UTC start of the next month
* - DELEGATED: accepted delegations are delegated at the UTC start of the month
* - UNDELEGATION_REQUESTED: token holder requests delegations to undelegate from the validator
* - COMPLETED: undelegation request is completed at the end of the delegation period
*/contractDelegationControllerisPermissions, ILocker{
usingMathUtilsforuint;
usingPartialDifferencesforPartialDifferences.Sequence;
usingPartialDifferencesforPartialDifferences.Value;
usingFractionUtilsforFractionUtils.Fraction;
enumState {
PROPOSED,
ACCEPTED,
CANCELED,
REJECTED,
DELEGATED,
UNDELEGATION_REQUESTED,
COMPLETED
}
structDelegation {
address holder; // address of token owneruint validatorId;
uint amount;
uint delegationPeriod;
uint created; // time of delegation creationuint started; // month when a delegation becomes activeuint finished; // first month after a delegation endsstring info;
}
structSlashingLogEvent {
FractionUtils.Fraction reducingCoefficient;
uint nextMonth;
}
structSlashingLog {
// month => slashing eventmapping (uint=> SlashingLogEvent) slashes;
uint firstMonth;
uint lastMonth;
}
structDelegationExtras {
uint lastSlashingMonthBeforeDelegation;
}
structSlashingEvent {
FractionUtils.Fraction reducingCoefficient;
uint validatorId;
uint month;
}
structSlashingSignal {
address holder;
uint penalty;
}
structLockedInPending {
uint amount;
uint month;
}
structFirstDelegationMonth {
// monthuint value;
//validatorId => monthmapping (uint=>uint) byValidator;
}
/**
* @dev Emitted when a delegation is proposed to a validator.
*/eventDelegationProposed(uint delegationId
);
/**
* @dev Emitted when a delegation is accepted by a validator.
*/eventDelegationAccepted(uint delegationId
);
/**
* @dev Emitted when a delegation is cancelled by the delegator.
*/eventDelegationRequestCanceledByUser(uint delegationId
);
/**
* @dev Emitted when a delegation is requested to undelegate.
*/eventUndelegationRequested(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 => extrasmapping(uint=> DelegationExtras) private _delegationExtras;
// validatorId => sequencemapping (uint=> PartialDifferences.Value) private _delegatedToValidator;
// validatorId => sequencemapping (uint=> PartialDifferences.Sequence) private _effectiveDelegatedToValidator;
// validatorId => slashing logmapping (uint=> SlashingLog) private _slashesOfValidator;
// holder => sequencemapping (address=> PartialDifferences.Value) private _delegatedByHolder;
// holder => validatorId => sequencemapping (address=>mapping (uint=> PartialDifferences.Value)) private _delegatedByHolderToValidator;
// holder => validatorId => sequencemapping (address=>mapping (uint=> PartialDifferences.Sequence)) private _effectiveDelegatedByHolderToValidator;
SlashingEvent[] private _slashes;
// holder => index in _slashes;mapping (address=>uint) private _firstUnprocessedSlashByHolder;
// holder => validatorId => monthmapping (address=> FirstDelegationMonth) private _firstDelegationMonth;
// holder => locked in pendingmapping (address=> LockedInPending) private _lockedInPendingDelegations;
/**
* @dev Modifier to make a function callable only if delegation exists.
*/modifiercheckDelegationExists(uint delegationId) {
require(delegationId < delegations.length, "Delegation does not exist");
_;
}
functiongetAndUpdateDelegatedToValidatorNow(uint validatorId) externalreturns (uint) {
return getAndUpdateDelegatedToValidator(validatorId, _getCurrentMonth());
}
functiongetAndUpdateDelegatedAmount(address holder) externalreturns (uint) {
return _getAndUpdateDelegatedByHolder(holder);
}
functiongetAndUpdateEffectiveDelegatedByHolderToValidator(address holder, uint validatorId, uint month) externalallow("Distributor") returns (uint effectiveDelegated)
{
SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(holder);
effectiveDelegated = _effectiveDelegatedByHolderToValidator[holder][validatorId]
.getAndUpdateValueInSequence(month);
_sendSlashingSignals(slashingSignals);
}
/**
* @dev Allows a token holder to create a delegation proposal of an `amount`
* and `delegationPeriod` to a `validatorId`. Delegation must be accepted
* by the validator before the UTC start of the month, otherwise the
* delegation will be rejected.
*
* The token holder may add additional information in each proposal.
*
* @param validatorId uint ID of validator to receive delegation proposal
* @param amount uint amount of proposed delegation
* @param delegationPeriod uint period of proposed delegation
* @param info string extra information provided by the token holder (if any)
*/functiondelegate(uint validatorId,
uint amount,
uint delegationPeriod,
stringcalldata info
)
external{
ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService"));
DelegationPeriodManager delegationPeriodManager = DelegationPeriodManager(
contractManager.getContract("DelegationPeriodManager"));
SkaleToken skaleToken = SkaleToken(contractManager.getContract("SkaleToken"));
TokenState tokenState = TokenState(contractManager.getContract("TokenState"));
require(
validatorService.checkMinimumDelegation(validatorId, amount),
"Amount does not meet the validator's minimum delegation amount");
require(
validatorService.isAuthorizedValidator(validatorId),
"Validator is not authorized to accept delegation request");
require(
delegationPeriodManager.isDelegationPeriodAllowed(delegationPeriod),
"This delegation period is not allowed");
require(
validatorService.isAcceptingNewRequests(validatorId),
"The validator is not currently accepting new requests");
SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(msg.sender);
uint delegationId = _addDelegation(
msg.sender,
validatorId,
amount,
delegationPeriod,
info);
// check that there is enough moneyuint holderBalance = skaleToken.balanceOf(msg.sender);
uint forbiddenForDelegation = tokenState.getAndUpdateForbiddenForDelegationAmount(msg.sender);
require(holderBalance >= forbiddenForDelegation, "Token holder does not have enough tokens to delegate");
emit DelegationProposed(delegationId);
_sendSlashingSignals(slashingSignals);
}
/**
* @dev See ILocker.
*/functiongetAndUpdateLockedAmount(address wallet) externaloverridereturns (uint) {
return _getAndUpdateLockedAmount(wallet);
}
/**
* @dev See ILocker.
*/functiongetAndUpdateForbiddenForDelegationAmount(address wallet) externaloverridereturns (uint) {
return _getAndUpdateLockedAmount(wallet);
}
/**
* @dev Allows a token holder to cancel a delegation proposal.
*
* Requirements:
*
* - the sender must be the token holder of the delegation proposal.
* - the delegation must still be in a PROPOSED state.
*
* Emits a DelegationRequestCanceledByUser event.
*
* @param delegationId uint ID of delegation proposal
*/functioncancelPendingDelegation(uint delegationId) externalcheckDelegationExists(delegationId) {
require(msg.sender== delegations[delegationId].holder, "Only token holders can cancel delegation request");
require(getState(delegationId) == State.PROPOSED, "Token holders are only able to cancel PROPOSED delegations");
delegations[delegationId].finished = _getCurrentMonth();
_subtractFromLockedInPendingDelegations(delegations[delegationId].holder, delegations[delegationId].amount);
emit DelegationRequestCanceledByUser(delegationId);
}
/**
* @dev Allows a validator to accept a proposed delegation.
* Successful acceptance of delegations transition the tokens from a
* PROPOSED state to ACCEPTED, and tokens are locked for the remainder of the
* delegation period.
*
* Emits a DelegationAccepted event.
*
* @param delegationId uint ID of delegation proposal
*/functionacceptPendingDelegation(uint delegationId) externalcheckDelegationExists(delegationId) {
ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService"));
require(
validatorService.checkValidatorAddressToId(msg.sender, delegations[delegationId].validatorId),
"No permissions to accept request");
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");
} elseif (currentState == State.CANCELED) {
revert("The delegation has been cancelled by token holder");
} elseif (currentState == State.REJECTED) {
revert("The delegation request is outdated");
}
}
require(currentState == State.PROPOSED, "Cannot set delegation state to accepted");
TokenLaunchLocker tokenLaunchLocker = TokenLaunchLocker(contractManager.getContract("TokenLaunchLocker"));
SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(delegations[delegationId].holder);
_addToAllStatistics(delegationId);
tokenLaunchLocker.handleDelegationAdd(
delegations[delegationId].holder,
delegationId,
delegations[delegationId].amount,
delegations[delegationId].started);
_sendSlashingSignals(slashingSignals);
emit DelegationAccepted(delegationId);
}
/**
* @dev Allows a delegator to undelegate a specific delegation.
*
* Requirements:
*
* - the sender must be the delegator.
* - the delegation must be in DELEGATED state.
*
* Emits an UndelegationRequested event.
*
* @param delegationId uint ID of delegation to undelegate
*/functionrequestUndelegation(uint delegationId) externalcheckDelegationExists(delegationId) {
require(getState(delegationId) == State.DELEGATED, "Cannot request undelegation");
ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService"));
require(
delegations[delegationId].holder ==msg.sender||
(validatorService.validatorAddressExists(msg.sender) &&
delegations[delegationId].validatorId == validatorService.getValidatorId(msg.sender)),
"Permission denied to request undelegation");
TokenLaunchLocker tokenLaunchLocker = TokenLaunchLocker(contractManager.getContract("TokenLaunchLocker"));
DelegationPeriodManager delegationPeriodManager = DelegationPeriodManager(
contractManager.getContract("DelegationPeriodManager"));
processAllSlashes(msg.sender);
delegations[delegationId].finished = _calculateDelegationEndMonth(delegationId);
uint amountAfterSlashing = _calculateDelegationAmountAfterSlashing(delegationId);
_removeFromDelegatedToValidator(
delegations[delegationId].validatorId,
amountAfterSlashing,
delegations[delegationId].finished);
_removeFromDelegatedByHolder(
delegations[delegationId].holder,
amountAfterSlashing,
delegations[delegationId].finished);
_removeFromDelegatedByHolderToValidator(
delegations[delegationId].holder,
delegations[delegationId].validatorId,
amountAfterSlashing,
delegations[delegationId].finished);
uint effectiveAmount = amountAfterSlashing.mul(delegationPeriodManager.stakeMultipliers(
delegations[delegationId].delegationPeriod));
_removeFromEffectiveDelegatedToValidator(
delegations[delegationId].validatorId,
effectiveAmount,
delegations[delegationId].finished);
_removeFromEffectiveDelegatedByHolderToValidator(
delegations[delegationId].holder,
delegations[delegationId].validatorId,
effectiveAmount,
delegations[delegationId].finished);
tokenLaunchLocker.handleDelegationRemoving(
delegations[delegationId].holder,
delegationId,
delegations[delegationId].finished);
emit UndelegationRequested(delegationId);
}
/**
* @dev Allows the Punisher to confiscate an `amount` of stake from
* `validatorId` by slashing. This slashes all delegations of the validator,
* which reduces the amount that the validator has staked. This consequence
* may force the SKALE Manger to reduce the number of nodes a validator is
* operating so the validator can meet the Minimum Staking Requirement.
*
* See Punisher.
*
* Emits a SlashingEvent.
*
* @param validatorId uint validator to slash
* @param amount uint amount to slash
*
*/functionconfiscate(uint validatorId, uint amount) externalallow("Punisher") {
uint currentMonth = _getCurrentMonth();
FractionUtils.Fraction memory coefficient =
_delegatedToValidator[validatorId].reduceValue(amount, currentMonth);
_effectiveDelegatedToValidator[validatorId].reduceSequence(coefficient, currentMonth);
_putToSlashingLog(_slashesOfValidator[validatorId], coefficient, currentMonth);
_slashes.push(SlashingEvent({reducingCoefficient: coefficient, validatorId: validatorId, month: currentMonth}));
}
functiongetAndUpdateEffectiveDelegatedToValidator(uint validatorId, uint month)
externalallow("Distributor") returns (uint)
{
return _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(month);
}
functiongetAndUpdateDelegatedByHolderToValidatorNow(address holder, uint validatorId) externalreturns (uint) {
return _getAndUpdateDelegatedByHolderToValidator(holder, validatorId, _getCurrentMonth());
}
functiongetDelegation(uint delegationId)
externalviewcheckDelegationExists(delegationId) returns (Delegation memory)
{
return delegations[delegationId];
}
functiongetFirstDelegationMonth(address holder, uint validatorId) externalviewreturns(uint) {
return _firstDelegationMonth[holder].byValidator[validatorId];
}
functiongetDelegationsByValidatorLength(uint validatorId) externalviewreturns (uint) {
return delegationsByValidator[validatorId].length;
}
functiongetDelegationsByHolderLength(address holder) externalviewreturns (uint) {
return delegationsByHolder[holder].length;
}
functioninitialize(address contractsAddress) publicoverrideinitializer{
Permissions.initialize(contractsAddress);
}
functiongetAndUpdateDelegatedToValidator(uint validatorId, uint month)
publicallow("Nodes") returns (uint)
{
return _delegatedToValidator[validatorId].getAndUpdateValue(month);
}
functionprocessSlashes(address holder, uint limit) public{
_sendSlashingSignals(_processSlashesWithoutSignals(holder, limit));
}
functionprocessAllSlashes(address holder) public{
processSlashes(holder, 0);
}
/**
* @dev Returns the token state of a given delegation.
*
* @param delegationId uint ID of the delegation
*/functiongetState(uint delegationId) publicviewcheckDelegationExists(delegationId) returns (State state) {
if (delegations[delegationId].started ==0) {
if (delegations[delegationId].finished ==0) {
TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers"));
if (_getCurrentMonth() == timeHelpers.timestampToMonth(delegations[delegationId].created)) {
return State.PROPOSED;
} else {
return State.REJECTED;
}
} else {
return State.CANCELED;
}
} else {
if (_getCurrentMonth() < delegations[delegationId].started) {
return State.ACCEPTED;
} else {
if (delegations[delegationId].finished ==0) {
return State.DELEGATED;
} else {
if (_getCurrentMonth() < delegations[delegationId].finished) {
return State.UNDELEGATION_REQUESTED;
} else {
return State.COMPLETED;
}
}
}
}
}
functiongetLockedInPendingDelegations(address holder) publicviewreturns (uint) {
uint currentMonth = _getCurrentMonth();
if (_lockedInPendingDelegations[holder].month < currentMonth) {
return0;
} else {
return _lockedInPendingDelegations[holder].amount;
}
}
functionhasUnprocessedSlashes(address holder) publicviewreturns (bool) {
return _everDelegated(holder) && _firstUnprocessedSlashByHolder[holder] < _slashes.length;
}
// privatefunction_addDelegation(address holder,
uint validatorId,
uint amount,
uint delegationPeriod,
stringmemory info
)
privatereturns (uint delegationId)
{
delegationId = delegations.length;
delegations.push(Delegation(
holder,
validatorId,
amount,
delegationPeriod,
now,
0,
0,
info
));
delegationsByValidator[validatorId].push(delegationId);
delegationsByHolder[holder].push(delegationId);
_addToLockedInPendingDelegations(delegations[delegationId].holder, delegations[delegationId].amount);
}
function_calculateDelegationEndMonth(uint delegationId) privateviewreturns (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_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_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) privatereturns (uint) {
uint currentMonth = _getCurrentMonth();
processAllSlashes(holder);
return _delegatedByHolder[holder].getAndUpdateValue(currentMonth);
}
function_getAndUpdateDelegatedByHolderToValidator(address holder,
uint validatorId,
uint month)
privatereturns (uint)
{
return _delegatedByHolderToValidator[holder][validatorId].getAndUpdateValue(month);
}
function_addToLockedInPendingDelegations(address holder, uint amount) privatereturns (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) privatereturns (uint) {
uint currentMonth = _getCurrentMonth();
require(
_lockedInPendingDelegations[holder].month == currentMonth,
"There are no delegation requests this month");
require(_lockedInPendingDelegations[holder].amount >= amount, "Unlocking amount is too big");
_lockedInPendingDelegations[holder].amount = _lockedInPendingDelegations[holder].amount.sub(amount);
}
function_getCurrentMonth() privateviewreturns (uint) {
TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers"));
return timeHelpers.getCurrentMonth();
}
function_getAndUpdateLockedAmount(address wallet) privatereturns (uint) {
return _getAndUpdateDelegatedByHolder(wallet).add(getLockedInPendingDelegations(wallet));
}
function_updateFirstDelegationMonth(address holder, uint validatorId, uint month) private{
if (_firstDelegationMonth[holder].value==0) {
_firstDelegationMonth[holder].value= month;
_firstUnprocessedSlashByHolder[holder] = _slashes.length;
}
if (_firstDelegationMonth[holder].byValidator[validatorId] ==0) {
_firstDelegationMonth[holder].byValidator[validatorId] = month;
}
}
function_everDelegated(address holder) privateviewreturns (bool) {
return _firstDelegationMonth[holder].value>0;
}
function_removeFromDelegatedToValidator(uint validatorId, uint amount, uint month) private{
_delegatedToValidator[validatorId].subtractFromValue(amount, month);
}
function_removeFromEffectiveDelegatedToValidator(uint validatorId, uint effectiveAmount, uint month) private{
_effectiveDelegatedToValidator[validatorId].subtractFromSequence(effectiveAmount, month);
}
function_calculateDelegationAmountAfterSlashing(uint delegationId) privateviewreturns (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)
privatereturns (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)
privatereturns (SlashingSignal[] memory slashingSignals)
{
return _processSlashesWithoutSignals(holder, 0);
}
function_sendSlashingSignals(SlashingSignal[] memory slashingSignals) private{
Punisher punisher = Punisher(contractManager.getContract("Punisher"));
address previousHolder =address(0);
uint accumulatedPenalty =0;
for (uint i =0; i < slashingSignals.length; ++i) {
if (slashingSignals[i].holder != previousHolder) {
if (accumulatedPenalty >0) {
punisher.handleSlash(previousHolder, accumulatedPenalty);
}
previousHolder = slashingSignals[i].holder;
accumulatedPenalty = slashingSignals[i].penalty;
} else {
accumulatedPenalty = accumulatedPenalty.add(slashingSignals[i].penalty);
}
}
if (accumulatedPenalty >0) {
punisher.handleSlash(previousHolder, accumulatedPenalty);
}
}
function_addToAllStatistics(uint delegationId) private{
DelegationPeriodManager delegationPeriodManager = DelegationPeriodManager(
contractManager.getContract("DelegationPeriodManager"));
uint currentMonth = _getCurrentMonth();
delegations[delegationId].started = currentMonth.add(1);
if (_slashesOfValidator[delegations[delegationId].validatorId].lastMonth >0) {
_delegationExtras[delegationId].lastSlashingMonthBeforeDelegation =
_slashesOfValidator[delegations[delegationId].validatorId].lastMonth;
}
_addToDelegatedToValidator(
delegations[delegationId].validatorId,
delegations[delegationId].amount,
currentMonth.add(1));
_addToDelegatedByHolder(
delegations[delegationId].holder,
delegations[delegationId].amount,
currentMonth.add(1));
_addToDelegatedByHolderToValidator(
delegations[delegationId].holder,
delegations[delegationId].validatorId,
delegations[delegationId].amount,
currentMonth.add(1));
_updateFirstDelegationMonth(
delegations[delegationId].holder,
delegations[delegationId].validatorId,
currentMonth.add(1));
uint effectiveAmount = delegations[delegationId].amount.mul(delegationPeriodManager.stakeMultipliers(
delegations[delegationId].delegationPeriod));
_addToEffectiveDelegatedToValidator(
delegations[delegationId].validatorId,
effectiveAmount,
currentMonth.add(1));
_addToEffectiveDelegatedByHolderToValidator(
delegations[delegationId].holder,
delegations[delegationId].validatorId,
effectiveAmount,
currentMonth.add(1));
}
}
Contract Source Code
File 5 of 36: DelegationPeriodManager.sol
// 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/>.
*/pragmasolidity 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.
*/contractDelegationPeriodManagerisPermissions{
/**
* @dev Emitted when a new delegation period is specified.
*/eventDelegationPeriodWasSet(uint length,
uint stakeMultiplier
);
mapping (uint=>uint) public stakeMultipliers;
/**
* @dev Creates a new available delegation period and return in the network.
* Only the owner may set new delegation period and returns in the network.
*
* Emits a DelegationPeriodWasSet event.
*
* @param monthsCount uint delegation duration in months
* @param stakeMultiplier uint return for delegation
*/functionsetDelegationPeriod(uint monthsCount, uint stakeMultiplier) externalonlyOwner{
stakeMultipliers[monthsCount] = stakeMultiplier;
emit DelegationPeriodWasSet(monthsCount, stakeMultiplier);
}
/**
* @dev Checks whether given delegation period is allowed.
*
* @param monthsCount uint delegation duration in months
* @return bool True if delegation period is allowed
*/functionisDelegationPeriodAllowed(uint monthsCount) externalviewreturns (bool) {
return stakeMultipliers[monthsCount] !=0 ? true : false;
}
/**
* @dev Initial delegation period and multiplier settings.
*/functioninitialize(address contractsAddress) publicoverrideinitializer{
Permissions.initialize(contractsAddress);
stakeMultipliers[3] =100; // 3 months at 100
stakeMultipliers[6] =150; // 6 months at 150
stakeMultipliers[12] =200; // 12 months at 200
}
}
Contract Source Code
File 6 of 36: ERC777.sol
pragmasolidity ^0.6.0;import"./OCContext.sol";
import"./OCIERC777.sol";
import"./OCIERC777Recipient.sol";
import"./OCIERC777Sender.sol";
import"./OCIERC20.sol";
import"./OCSafeMath.sol";
// import "@openzeppelin/contracts/utils/Address.sol"; Removed by SKALEimport"./OCIERC1820Registry.sol";
/* Added by SKALE */import"./Permissions.sol";
/* End of added by SKALE *//**
* @dev Implementation of the {IERC777} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* Support for ERC20 is included in this contract, as specified by the EIP: both
* the ERC777 and ERC20 interfaces can be safely used when interacting with it.
* Both {IERC777-Sent} and {IERC20-Transfer} events are emitted on token
* movements.
*
* Additionally, the {IERC777-granularity} value is hard-coded to `1`, meaning that there
* are no special restrictions in the amount of tokens that created, moved, or
* destroyed. This makes integration with ERC20 applications seamless.
*/contractERC777isContext, IERC777, IERC20{
usingSafeMathforuint256;
usingAddressforaddress;
IERC1820Registry constantinternal _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
mapping(address=>uint256) private _balances;
uint256private _totalSupply;
stringprivate _name;
stringprivate _symbol;
// We inline the result of the following hashes because Solidity doesn't resolve them at compile time.// See https://github.com/ethereum/solidity/issues/4024.// keccak256("ERC777TokensSender")bytes32constantprivate _TOKENS_SENDER_INTERFACE_HASH =0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;
// keccak256("ERC777TokensRecipient")bytes32constantprivate _TOKENS_RECIPIENT_INTERFACE_HASH =0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;
// This isn't ever read from - it's only used to respond to the defaultOperators query.address[] private _defaultOperatorsArray;
// Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).mapping(address=>bool) private _defaultOperators;
// For each account, a mapping of its operators and revoked default operators.mapping(address=>mapping(address=>bool)) private _operators;
mapping(address=>mapping(address=>bool)) private _revokedDefaultOperators;
// ERC20-allowancesmapping (address=>mapping (address=>uint256)) private _allowances;
/**
* @dev `defaultOperators` may be an empty array.
*/constructor(stringmemory name,
stringmemory symbol,
address[] memory defaultOperators
) public{
_name = name;
_symbol = symbol;
_defaultOperatorsArray = defaultOperators;
for (uint256 i =0; i < _defaultOperatorsArray.length; i++) {
_defaultOperators[_defaultOperatorsArray[i]] =true;
}
// register interfaces
_ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this));
_ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC20Token"), address(this));
}
/**
* @dev See {IERC777-name}.
*/functionname() publicviewoverridereturns (stringmemory) {
return _name;
}
/**
* @dev See {IERC777-symbol}.
*/functionsymbol() publicviewoverridereturns (stringmemory) {
return _symbol;
}
/**
* @dev See {ERC20-decimals}.
*
* Always returns 18, as per the
* [ERC777 EIP](https://eips.ethereum.org/EIPS/eip-777#backward-compatibility).
*/functiondecimals() publicpurereturns (uint8) {
return18;
}
/**
* @dev See {IERC777-granularity}.
*
* This implementation always returns `1`.
*/functiongranularity() publicviewoverridereturns (uint256) {
return1;
}
/**
* @dev See {IERC777-totalSupply}.
*/functiontotalSupply() publicviewoverride(IERC20, IERC777) returns (uint256) {
return _totalSupply;
}
/**
* @dev Returns the amount of tokens owned by an account (`tokenHolder`).
*/functionbalanceOf(address tokenHolder) publicviewoverride(IERC20, IERC777) returns (uint256) {
return _balances[tokenHolder];
}
/**
* @dev See {IERC777-send}.
*
* Also emits a {IERC20-Transfer} event for ERC20 compatibility.
*/functionsend(address recipient, uint256 amount, bytesmemory data) publicoverride{
_send(_msgSender(), recipient, amount, data, "", true);
}
/**
* @dev See {IERC20-transfer}.
*
* Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}
* interface if it is a contract.
*
* Also emits a {Sent} event.
*/functiontransfer(address recipient, uint256 amount) publicoverridereturns (bool) {
require(recipient !=address(0), "ERC777: transfer to the zero address");
addressfrom= _msgSender();
_callTokensToSend(from, from, recipient, amount, "", "");
_move(from, from, recipient, amount, "", "");
_callTokensReceived(from, from, recipient, amount, "", "", false);
returntrue;
}
/**
* @dev See {IERC777-burn}.
*
* Also emits a {IERC20-Transfer} event for ERC20 compatibility.
*/functionburn(uint256 amount, bytesmemory data) publicoverride{
_burn(_msgSender(), amount, data, "");
}
/**
* @dev See {IERC777-isOperatorFor}.
*/functionisOperatorFor(address operator,
address tokenHolder
) publicviewoverridereturns (bool) {
return operator == tokenHolder ||
(_defaultOperators[operator] &&!_revokedDefaultOperators[tokenHolder][operator]) ||
_operators[tokenHolder][operator];
}
/**
* @dev See {IERC777-authorizeOperator}.
*/functionauthorizeOperator(address operator) publicoverride{
require(_msgSender() != operator, "ERC777: authorizing self as operator");
if (_defaultOperators[operator]) {
delete _revokedDefaultOperators[_msgSender()][operator];
} else {
_operators[_msgSender()][operator] =true;
}
emit AuthorizedOperator(operator, _msgSender());
}
/**
* @dev See {IERC777-revokeOperator}.
*/functionrevokeOperator(address operator) publicoverride{
require(operator != _msgSender(), "ERC777: revoking self as operator");
if (_defaultOperators[operator]) {
_revokedDefaultOperators[_msgSender()][operator] =true;
} else {
delete _operators[_msgSender()][operator];
}
emit RevokedOperator(operator, _msgSender());
}
/**
* @dev See {IERC777-defaultOperators}.
*/functiondefaultOperators() publicviewoverridereturns (address[] memory) {
return _defaultOperatorsArray;
}
/**
* @dev See {IERC777-operatorSend}.
*
* Emits {Sent} and {IERC20-Transfer} events.
*/functionoperatorSend(address sender,
address recipient,
uint256 amount,
bytesmemory data,
bytesmemory operatorData
)
publicoverride{
require(isOperatorFor(_msgSender(), sender), "ERC777: caller is not an operator for holder");
_send(sender, recipient, amount, data, operatorData, true);
}
/**
* @dev See {IERC777-operatorBurn}.
*
* Emits {Burned} and {IERC20-Transfer} events.
*/functionoperatorBurn(address account, uint256 amount, bytesmemory data, bytesmemory operatorData) publicoverride{
require(isOperatorFor(_msgSender(), account), "ERC777: caller is not an operator for holder");
_burn(account, amount, data, operatorData);
}
/**
* @dev See {IERC20-allowance}.
*
* Note that operator and allowance concepts are orthogonal: operators may
* not have allowance, and accounts with allowance may not be operators
* themselves.
*/functionallowance(address holder, address spender) publicviewoverridereturns (uint256) {
return _allowances[holder][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Note that accounts cannot have allowance issued by their operators.
*/functionapprove(address spender, uint256 value) publicoverridereturns (bool) {
address holder = _msgSender();
_approve(holder, spender, value);
returntrue;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Note that operator and allowance concepts are orthogonal: operators cannot
* call `transferFrom` (unless they have allowance), and accounts with
* allowance cannot call `operatorSend` (unless they are operators).
*
* Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.
*/functiontransferFrom(address holder, address recipient, uint256 amount) publicoverridereturns (bool) {
require(recipient !=address(0), "ERC777: transfer to the zero address");
require(holder !=address(0), "ERC777: transfer from the zero address");
address spender = _msgSender();
_callTokensToSend(spender, holder, recipient, amount, "", "");
_move(spender, holder, recipient, amount, "", "");
_approve(holder, spender, _allowances[holder][spender].sub(amount, "ERC777: transfer amount exceeds allowance"));
_callTokensReceived(spender, holder, recipient, amount, "", "", false);
returntrue;
}
/**
* @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* If a send hook is registered for `account`, the corresponding function
* will be called with `operator`, `data` and `operatorData`.
*
* See {IERC777Sender} and {IERC777Recipient}.
*
* Emits {Minted} and {IERC20-Transfer} events.
*
* Requirements
*
* - `account` cannot be the zero address.
* - if `account` is a contract, it must implement the {IERC777Recipient}
* interface.
*/function_mint(address account,
uint256 amount,
bytesmemory userData,
bytesmemory operatorData
)
internalvirtual{
require(account !=address(0), "ERC777: mint to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), account, amount);
// Update state variables
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
_callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);
emit Minted(operator, account, amount, userData, operatorData);
emit Transfer(address(0), account, amount);
}
/**
* @dev Send tokens
* @param from address token holder address
* @param to address recipient address
* @param amount uint256 amount of tokens to transfer
* @param userData bytes extra information provided by the token holder (if any)
* @param operatorData bytes extra information provided by the operator (if any)
* @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient
*/function_send(addressfrom,
address to,
uint256 amount,
bytesmemory userData,
bytesmemory operatorData,
bool requireReceptionAck
)
internal{
require(from!=address(0), "ERC777: send from the zero address");
require(to !=address(0), "ERC777: send to the zero address");
address operator = _msgSender();
_callTokensToSend(operator, from, to, amount, userData, operatorData);
_move(operator, from, to, amount, userData, operatorData);
_callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck);
}
/**
* @dev Burn tokens
* @param from address token holder address
* @param amount uint256 amount of tokens to burn
* @param data bytes extra information provided by the token holder
* @param operatorData bytes extra information provided by the operator (if any)
*/function_burn(addressfrom,
uint256 amount,
bytesmemory data,
bytesmemory operatorData
)
internalvirtual{
require(from!=address(0), "ERC777: burn from the zero address");
address operator = _msgSender();
/* Chaged by SKALE: we swapped these lines to prevent delegation of burning tokens */
_callTokensToSend(operator, from, address(0), amount, data, operatorData);
_beforeTokenTransfer(operator, from, address(0), amount);
/* End of changed by SKALE */// Update state variables
_balances[from] = _balances[from].sub(amount, "ERC777: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Burned(operator, from, amount, data, operatorData);
emit Transfer(from, address(0), amount);
}
function_move(address operator,
addressfrom,
address to,
uint256 amount,
bytesmemory userData,
bytesmemory operatorData
)
private{
_beforeTokenTransfer(operator, from, to, amount);
_balances[from] = _balances[from].sub(amount, "ERC777: transfer amount exceeds balance");
_balances[to] = _balances[to].add(amount);
emit Sent(operator, from, to, amount, userData, operatorData);
emit Transfer(from, to, amount);
}
/**
* @dev See {ERC20-_approve}.
*
* Note that accounts cannot have allowance issued by their operators.
*/function_approve(address holder, address spender, uint256 value) internal{
require(holder !=address(0), "ERC777: approve from the zero address");
require(spender !=address(0), "ERC777: approve to the zero address");
_allowances[holder][spender] = value;
emit Approval(holder, spender, value);
}
/**
* @dev Call from.tokensToSend() if the interface is registered
* @param operator address operator requesting the transfer
* @param from address token holder address
* @param to address recipient address
* @param amount uint256 amount of tokens to transfer
* @param userData bytes extra information provided by the token holder (if any)
* @param operatorData bytes extra information provided by the operator (if any)
*/function_callTokensToSend(address operator,
addressfrom,
address to,
uint256 amount,
bytesmemory userData,
bytesmemory operatorData
)
/* Chaged by SKALE from private */internal/* End of changed by SKALE *//* Added by SKALE */virtual/* End of added by SKALE */{
address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(from, _TOKENS_SENDER_INTERFACE_HASH);
if (implementer !=address(0)) {
IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData);
}
}
/**
* @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but
* tokensReceived() was not registered for the recipient
* @param operator address operator requesting the transfer
* @param from address token holder address
* @param to address recipient address
* @param amount uint256 amount of tokens to transfer
* @param userData bytes extra information provided by the token holder (if any)
* @param operatorData bytes extra information provided by the operator (if any)
* @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient
*/function_callTokensReceived(address operator,
addressfrom,
address to,
uint256 amount,
bytesmemory userData,
bytesmemory operatorData,
bool requireReceptionAck
)
/* Chaged by SKALE from private */internal/* End of changed by SKALE *//* Added by SKALE */virtual/* End of added by SKALE */{
address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(to, _TOKENS_RECIPIENT_INTERFACE_HASH);
if (implementer !=address(0)) {
IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData);
} elseif (requireReceptionAck) {
require(!to.isContract(), "ERC777: token recipient contract has no implementer for ERC777TokensRecipient");
}
}
/**
* @dev Hook that is called before any token transfer. This includes
* calls to {send}, {transfer}, {operatorSend}, minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, ``from``'s `tokenId` will be
* transferred to `to`.
* - when `from` is zero, `tokenId` will be minted for `to`.
* - when `to` is zero, ``from``'s `tokenId` will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/function_beforeTokenTransfer(address operator, addressfrom, address to, uint256 tokenId) internalvirtual{ }
}
Contract Source Code
File 7 of 36: FractionUtils.sol
// 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/>.
*/pragmasolidity 0.6.10;import"./OCSafeMath.sol";
libraryFractionUtils{
usingSafeMathforuint;
structFraction {
uint numerator;
uint denominator;
}
functioncreateFraction(uint numerator, uint denominator) internalpurereturns (Fraction memory) {
require(denominator >0, "Division by zero");
Fraction memory fraction = Fraction({numerator: numerator, denominator: denominator});
reduceFraction(fraction);
return fraction;
}
functioncreateFraction(uint value) internalpurereturns (Fraction memory) {
return createFraction(value, 1);
}
functionreduceFraction(Fraction memory fraction) internalpure{
uint _gcd = gcd(fraction.numerator, fraction.denominator);
fraction.numerator = fraction.numerator.div(_gcd);
fraction.denominator = fraction.denominator.div(_gcd);
}
functionmultiplyFraction(Fraction memory a, Fraction memory b) internalpurereturns (Fraction memory) {
return createFraction(a.numerator.mul(b.numerator), a.denominator.mul(b.denominator));
}
functiongcd(uint a, uint b) internalpurereturns (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;
}
functionswap(uint a, uint b) internalpurereturns (uint, uint) {
return (b, a);
}
}
Contract Source Code
File 8 of 36: IDelegatableToken.sol
// SPDX-License-Identifier: AGPL-3.0-only/*
IDelegatableToken.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/>.
*/pragmasolidity 0.6.10;/**
* @dev Interface of Delegatable Token operations.
*/interfaceIDelegatableToken{
/**
* @dev Updates and returns the amount of locked tokens of a given account (`wallet`).
*/functiongetAndUpdateLockedAmount(address wallet) externalreturns (uint);
/**
* @dev Updates and returns the amount of delegated tokens of a given account (`wallet`).
*/functiongetAndUpdateDelegatedAmount(address wallet) externalreturns (uint);
/**
* @dev Updates and returns the amount of slashed tokens of a given account (`wallet`).
*/functiongetAndUpdateSlashedAmount(address wallet) externalreturns (uint);
}
Contract Source Code
File 9 of 36: ILocker.sol
// 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/>.
*/pragmasolidity 0.6.10;/**
* @dev Interface of Locker functions of the {TokenState} contract.
*
* The SKALE Network has three types of locked tokens:
*
* - Tokens that are transferrable but are currently locked into delegation with
* a validator. See {DelegationController};
*
* - Tokens that are not transferable from one address to another, but may be
* delegated to a validator {getAndUpdateLockedAmount}. This lock enforces
* Proof-of-Use requirements. See {TokenLaunchLocker}; and,
*
* - Tokens that are neither transferable nor delegatable
* {getAndUpdateForbiddenForDelegationAmount}. This lock enforces slashing.
* See {Punisher}.
*/interfaceILocker{
/**
* @dev Returns the locked amount of untransferable tokens of a given `wallet`
*/functiongetAndUpdateLockedAmount(address wallet) externalreturns (uint);
/**
* @dev Returns the locked amount of untransferable and un-delegatable tokens of a given `wallet`.
*/functiongetAndUpdateForbiddenForDelegationAmount(address wallet) externalreturns (uint);
}
Contract Source Code
File 10 of 36: MathUtils.sol
// 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/>.
*/pragmasolidity 0.6.10;libraryMathUtils{
eventUnderflowError(uint a,
uint b
);
uintconstantprivate _EPS =1e6;
functionboundedSub(uint256 a, uint256 b) internalreturns (uint256) {
if (a >= b) {
return a - b;
} else {
emit UnderflowError(a, b);
return0;
}
}
functionboundedSubWithoutEvent(uint256 a, uint256 b) internalpurereturns (uint256) {
if (a >= b) {
return a - b;
} else {
return0;
}
}
functionmuchGreater(uint256 a, uint256 b) internalpurereturns (bool) {
assert(uint(-1) - _EPS > b);
return a > b + _EPS;
}
functionapproximatelyEqual(uint256 a, uint256 b) internalpurereturns (bool) {
if (a > b) {
return a - b < _EPS;
} else {
return b - a < _EPS;
}
}
}
Contract Source Code
File 11 of 36: Nodes.sol
// SPDX-License-Identifier: AGPL-3.0-only/*
Nodes.sol - SKALE Manager
Copyright (C) 2018-Present SKALE Labs
@author Artem Payvin
SKALE Manager is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SKALE Manager is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>.
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;import"./OCSafeCast.sol";
import"./Permissions.sol";
import"./ConstantsHolder.sol";
import"./ValidatorService.sol";
import"./DelegationController.sol";
/**
* @title Nodes - contract contains all functionality logic to manage Nodes
*/contractNodesisPermissions{
usingSafeCastforuint;
// All Nodes statesenumNodeStatus {Active, Leaving, Left}
structNode {
string name;
bytes4 ip;
bytes4 publicIP;
uint16 port;
bytes32[2] publicKey;
uint startBlock;
uint lastRewardDate;
uint finishTime;
NodeStatus status;
uint validatorId;
}
// struct to note which Nodes and which number of Nodes owned by userstructCreatedNodes {
mapping (uint=>bool) isNodeExist;
uint numberOfNodes;
}
structSpaceManaging {
uint8 freeSpace;
uint indexInSpaceMap;
}
// TODO: move outside the contractstructNodeCreationParams {
string name;
bytes4 ip;
bytes4 publicIp;
uint16 port;
bytes32[2] publicKey;
uint16 nonce;
}
// array which contain all Nodes
Node[] public nodes;
SpaceManaging[] public spaceOfNodes;
// mapping for checking which Nodes and which number of Nodes owned by usermapping (address=> CreatedNodes) public nodeIndexes;
// mapping for checking is IP address busymapping (bytes4=>bool) public nodesIPCheck;
// mapping for checking is Name busymapping (bytes32=>bool) public nodesNameCheck;
// mapping for indication from Name to Indexmapping (bytes32=>uint) public nodesNameToIndex;
// mapping for indication from space to Nodesmapping (uint8=>uint[]) public spaceToNodes;
mapping (uint=>uint[]) public validatorToNodeIndexes;
uintpublic numberOfActiveNodes;
uintpublic numberOfLeavingNodes;
uintpublic numberOfLeftNodes;
// informs that Node is createdeventNodeCreated(uint nodeIndex,
address owner,
string name,
bytes4 ip,
bytes4 publicIP,
uint16 port,
uint16 nonce,
uint time,
uint gasSpend
);
// informs that node is fully finished quitting from the systemeventExitCompleted(uint nodeIndex,
uint time,
uint gasSpend
);
// informs that owner starts the procedure of quitting the Node from the systemeventExitInited(uint nodeIndex,
uint startLeavingPeriod,
uint time,
uint gasSpend
);
/**
* @dev removeSpaceFromFractionalNode - occupies space from Fractional Node
* function could be run only by Schains
* @param nodeIndex - index of Node at array of Fractional Nodes
* @param space - space which should be occupied
*/functionremoveSpaceFromNode(uint nodeIndex, uint8 space)
externalallowTwo("NodeRotation", "SchainsInternal")
returns (bool)
{
if (spaceOfNodes[nodeIndex].freeSpace < space) {
returnfalse;
}
if (space >0) {
_moveNodeToNewSpaceMap(
nodeIndex,
uint(spaceOfNodes[nodeIndex].freeSpace).sub(space).toUint8()
);
}
returntrue;
}
/**
* @dev adSpaceToFractionalNode - returns space to Fractional Node
* function could be run only be Schains
* @param nodeIndex - index of Node at array of Fractional Nodes
* @param space - space which should be returned
*/functionaddSpaceToNode(uint nodeIndex, uint8 space) externalallow("Schains") {
if (space >0) {
_moveNodeToNewSpaceMap(
nodeIndex,
uint(spaceOfNodes[nodeIndex].freeSpace).add(space).toUint8()
);
}
}
/**
* @dev changeNodeLastRewardDate - changes Node's last reward date
* function could be run only by SkaleManager
* @param nodeIndex - index of Node
*/functionchangeNodeLastRewardDate(uint nodeIndex) externalallow("SkaleManager") {
nodes[nodeIndex].lastRewardDate =block.timestamp;
}
functionchangeNodeFinishTime(uint nodeIndex, uint time) externalallow("SkaleManager") {
nodes[nodeIndex].finishTime = time;
}
/**
* @dev createNode - creates new Node and add it to the Nodes contract
* function could be only run by SkaleManager
* @param from - owner of Node
* @return nodeIndex - index of Node
*/functioncreateNode(addressfrom, NodeCreationParams calldata params)
externalallow("SkaleManager")
returns (uint nodeIndex)
{
// checks that Node has correct datarequire(params.ip !=0x0&&!nodesIPCheck[params.ip], "IP address is zero or is not available");
require(!nodesNameCheck[keccak256(abi.encodePacked(params.name))], "Name has already registered");
require(params.port >0, "Port is zero");
uint validatorId = ValidatorService(
contractManager.getContract("ValidatorService")).getValidatorIdByNodeAddress(from);
// adds Node to Nodes contract
nodeIndex = _addNode(
from,
params.name,
params.ip,
params.publicIp,
params.port,
params.publicKey,
validatorId);
emit NodeCreated(
nodeIndex,
from,
params.name,
params.ip,
params.publicIp,
params.port,
params.nonce,
block.timestamp,
gasleft());
}
/**
* @dev initExit - initiate a procedure of quitting the system
* function could be only run by SkaleManager
* @param nodeIndex - index of Node
* @return true - if everything OK
*/functioninitExit(uint nodeIndex) externalallow("SkaleManager") returns (bool) {
_setNodeLeaving(nodeIndex);
emit ExitInited(
nodeIndex,
block.timestamp,
block.timestamp,
gasleft());
returntrue;
}
/**
* @dev completeExit - finish a procedure of quitting the system
* function could be run only by SkaleManager
* @param nodeIndex - index of Node
* @return amount of SKL which be returned
*/functioncompleteExit(uint nodeIndex) externalallow("SkaleManager") returns (bool) {
require(isNodeLeaving(nodeIndex), "Node is not Leaving");
_setNodeLeft(nodeIndex);
_deleteNode(nodeIndex);
emit ExitCompleted(
nodeIndex,
block.timestamp,
gasleft());
returntrue;
}
functiondeleteNodeForValidator(uint validatorId, uint nodeIndex) externalallow("SkaleManager") {
ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService"));
require(validatorService.validatorExists(validatorId), "Validator with such ID does not exist");
uint[] memory validatorNodes = validatorToNodeIndexes[validatorId];
uint position = _findNode(validatorNodes, nodeIndex);
if (position < validatorNodes.length) {
validatorToNodeIndexes[validatorId][position] =
validatorToNodeIndexes[validatorId][validatorNodes.length.sub(1)];
}
validatorToNodeIndexes[validatorId].pop();
}
functioncheckPossibilityCreatingNode(address nodeAddress) externalallow("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");
}
functioncheckPossibilityToMaintainNode(uint validatorId,
uint nodeIndex
)
externalallow("Bounty")
returns (bool)
{
DelegationController delegationController = DelegationController(
contractManager.getContract("DelegationController")
);
ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService"));
require(validatorService.validatorExists(validatorId), "Validator with such ID does not exist");
uint[] memory validatorNodes = validatorToNodeIndexes[validatorId];
uint position = _findNode(validatorNodes, nodeIndex);
require(position < validatorNodes.length, "Node does not exist for this Validator");
uint delegationsTotal = delegationController.getAndUpdateDelegatedToValidatorNow(validatorId);
uint msr = ConstantsHolder(contractManager.getContract("ConstantsHolder")).msr();
return position.add(1).mul(msr) <= delegationsTotal;
}
functiongetNodesWithFreeSpace(uint8 freeSpace) externalviewreturns (uint[] memory) {
ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder"));
uint[] memory nodesWithFreeSpace =newuint[](countNodesWithFreeSpace(freeSpace));
uint cursor =0;
for (uint8 i = freeSpace; i <= constantsHolder.TOTAL_SPACE_ON_NODE(); ++i) {
for (uint j =0; j < spaceToNodes[i].length; j++) {
nodesWithFreeSpace[cursor] = spaceToNodes[i][j];
++cursor;
}
}
return nodesWithFreeSpace;
}
/**
* @dev isTimeForReward - checks if time for reward has come
* @param nodeIndex - index of Node
* @return if time for reward has come - true, else - false
*/functionisTimeForReward(uint nodeIndex) externalviewreturns (bool) {
ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder"));
returnuint(nodes[nodeIndex].lastRewardDate).add(constantsHolder.rewardPeriod()) <=block.timestamp;
}
/**
* @dev isNodeExist - checks existence of Node at this address
* @param from - account address
* @param nodeIndex - index of Node
* @return if exist - true, else - false
*/functionisNodeExist(addressfrom, uint nodeIndex) externalviewreturns (bool) {
return nodeIndexes[from].isNodeExist[nodeIndex];
}
/**
* @dev getNodeIP - get ip address of Node
* @param nodeIndex - index of Node
* @return ip address
*/functiongetNodeIP(uint nodeIndex) externalviewreturns (bytes4) {
require(nodeIndex < nodes.length, "Node does not exist");
return nodes[nodeIndex].ip;
}
/**
* @dev getNodePort - get Node's port
* @param nodeIndex - index of Node
* @return port
*/functiongetNodePort(uint nodeIndex) externalviewreturns (uint16) {
return nodes[nodeIndex].port;
}
functiongetNodePublicKey(uint nodeIndex) externalviewreturns (bytes32[2] memory) {
return nodes[nodeIndex].publicKey;
}
functiongetNodeFinishTime(uint nodeIndex) externalviewreturns (uint) {
return nodes[nodeIndex].finishTime;
}
/**
* @dev isNodeLeft - checks if Node status Left
* @param nodeIndex - index of Node
* @return if Node status Left - true, else - false
*/functionisNodeLeft(uint nodeIndex) externalviewreturns (bool) {
return nodes[nodeIndex].status == NodeStatus.Left;
}
/**
* @dev getNodeLastRewardDate - get Node last reward date
* @param nodeIndex - index of Node
* @return Node last reward date
*/functiongetNodeLastRewardDate(uint nodeIndex) externalviewreturns (uint) {
return nodes[nodeIndex].lastRewardDate;
}
/**
* @dev getNodeNextRewardDate - get Node next reward date
* @param nodeIndex - index of Node
* @return Node next reward date
*/functiongetNodeNextRewardDate(uint nodeIndex) externalviewreturns (uint) {
ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder"));
return nodes[nodeIndex].lastRewardDate.add(constantsHolder.rewardPeriod());
}
/**
* @dev getNumberOfNodes - get number of Nodes
* @return number of Nodes
*/functiongetNumberOfNodes() externalviewreturns (uint) {
return nodes.length;
}
/**
* @dev getNumberOfFullNodes - get number Online Nodes
* @return number of active nodes plus number of leaving nodes
*/functiongetNumberOnlineNodes() externalviewreturns (uint) {
return numberOfActiveNodes.add(numberOfLeavingNodes);
}
/**
* @dev getActiveNodeIPs - get array of ips of Active Nodes
* @return activeNodeIPs - array of ips of Active Nodes
*/functiongetActiveNodeIPs() externalviewreturns (bytes4[] memory activeNodeIPs) {
activeNodeIPs =newbytes4[](numberOfActiveNodes);
uint indexOfActiveNodeIPs =0;
for (uint indexOfNodes =0; indexOfNodes < nodes.length; indexOfNodes++) {
if (isNodeActive(indexOfNodes)) {
activeNodeIPs[indexOfActiveNodeIPs] = nodes[indexOfNodes].ip;
indexOfActiveNodeIPs++;
}
}
}
/**
* @dev getActiveNodesByAddress - get array of indexes of Active Nodes, which were
* created by msg.sender
* @return activeNodesByAddress Array of indexes of Active Nodes, which were created by msg.sender
*/functiongetActiveNodesByAddress() externalviewreturns (uint[] memory activeNodesByAddress) {
activeNodesByAddress =newuint[](nodeIndexes[msg.sender].numberOfNodes);
uint indexOfActiveNodesByAddress =0;
for (uint indexOfNodes =0; indexOfNodes < nodes.length; indexOfNodes++) {
if (nodeIndexes[msg.sender].isNodeExist[indexOfNodes] && isNodeActive(indexOfNodes)) {
activeNodesByAddress[indexOfActiveNodesByAddress] = indexOfNodes;
indexOfActiveNodesByAddress++;
}
}
}
/**
* @dev getActiveNodeIds - get array of indexes of Active Nodes
* @return activeNodeIds - array of indexes of Active Nodes
*/functiongetActiveNodeIds() externalviewreturns (uint[] memory activeNodeIds) {
activeNodeIds =newuint[](numberOfActiveNodes);
uint indexOfActiveNodeIds =0;
for (uint indexOfNodes =0; indexOfNodes < nodes.length; indexOfNodes++) {
if (isNodeActive(indexOfNodes)) {
activeNodeIds[indexOfActiveNodeIds] = indexOfNodes;
indexOfActiveNodeIds++;
}
}
}
functiongetValidatorId(uint nodeIndex) externalviewreturns (uint) {
require(nodeIndex < nodes.length, "Node does not exist");
return nodes[nodeIndex].validatorId;
}
functiongetNodeStatus(uint nodeIndex) externalviewreturns (NodeStatus) {
return nodes[nodeIndex].status;
}
functiongetValidatorNodeIndexes(uint validatorId) externalviewreturns (uint[] memory) {
ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService"));
require(validatorService.validatorExists(validatorId), "Validator with such ID does not exist");
return validatorToNodeIndexes[validatorId];
}
/**
* @dev constructor in Permissions approach
* @param contractsAddress needed in Permissions constructor
*/functioninitialize(address contractsAddress) publicoverrideinitializer{
Permissions.initialize(contractsAddress);
numberOfActiveNodes =0;
numberOfLeavingNodes =0;
numberOfLeftNodes =0;
}
/**
* @dev isNodeActive - checks if Node status Active
* @param nodeIndex - index of Node
* @return if Node status Active - true, else - false
*/functionisNodeActive(uint nodeIndex) publicviewreturns (bool) {
return nodes[nodeIndex].status == NodeStatus.Active;
}
/**
* @dev isNodeLeaving - checks if Node status Leaving
* @param nodeIndex - index of Node
* @return if Node status Leaving - true, else - false
*/functionisNodeLeaving(uint nodeIndex) publicviewreturns (bool) {
return nodes[nodeIndex].status == NodeStatus.Leaving;
}
functioncountNodesWithFreeSpace(uint8 freeSpace) publicviewreturns (uint count) {
ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder"));
count =0;
for (uint8 i = freeSpace; i <= constantsHolder.TOTAL_SPACE_ON_NODE(); ++i) {
count = count.add(spaceToNodes[i].length);
}
}
function_findNode(uint[] memory validatorNodeIndexes, uint nodeIndex) privatepurereturns (uint) {
uint i;
for (i =0; i < validatorNodeIndexes.length; i++) {
if (validatorNodeIndexes[i] == nodeIndex) {
return i;
}
}
return validatorNodeIndexes.length;
}
function_moveNodeToNewSpaceMap(uint nodeIndex, uint8 newSpace) private{
uint8 previousSpace = spaceOfNodes[nodeIndex].freeSpace;
uint indexInArray = spaceOfNodes[nodeIndex].indexInSpaceMap;
if (indexInArray < spaceToNodes[previousSpace].length.sub(1)) {
uint shiftedIndex = spaceToNodes[previousSpace][spaceToNodes[previousSpace].length.sub(1)];
spaceToNodes[previousSpace][indexInArray] = shiftedIndex;
spaceOfNodes[shiftedIndex].indexInSpaceMap = indexInArray;
spaceToNodes[previousSpace].pop();
} else {
spaceToNodes[previousSpace].pop();
}
spaceToNodes[newSpace].push(nodeIndex);
spaceOfNodes[nodeIndex].freeSpace = newSpace;
spaceOfNodes[nodeIndex].indexInSpaceMap = spaceToNodes[newSpace].length.sub(1);
}
/**
* @dev _setNodeLeft - set Node Left
* function could be run only by Nodes
* @param nodeIndex - index of Node
*/function_setNodeLeft(uint nodeIndex) private{
nodesIPCheck[nodes[nodeIndex].ip] =false;
nodesNameCheck[keccak256(abi.encodePacked(nodes[nodeIndex].name))] =false;
delete nodesNameToIndex[keccak256(abi.encodePacked(nodes[nodeIndex].name))];
if (nodes[nodeIndex].status == NodeStatus.Active) {
numberOfActiveNodes--;
} else {
numberOfLeavingNodes--;
}
nodes[nodeIndex].status = NodeStatus.Left;
numberOfLeftNodes++;
}
/**
* @dev _setNodeLeaving - set Node Leaving
* function could be run only by Nodes
* @param nodeIndex - index of Node
*/function_setNodeLeaving(uint nodeIndex) private{
nodes[nodeIndex].status = NodeStatus.Leaving;
numberOfActiveNodes--;
numberOfLeavingNodes++;
}
/**
* @dev _addNode - adds Node to array
* function could be run only by executor
* @param from - owner of Node
* @param name - Node name
* @param ip - Node ip
* @param publicIP - Node public ip
* @param port - Node public port
* @param publicKey - Ethereum public key
* @return nodeIndex Index of Node
*/function_addNode(addressfrom,
stringmemory name,
bytes4 ip,
bytes4 publicIP,
uint16 port,
bytes32[2] memory publicKey,
uint validatorId
)
privatereturns (uint nodeIndex)
{
ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder"));
nodes.push(Node({
name: name,
ip: ip,
publicIP: publicIP,
port: port,
//owner: from,
publicKey: publicKey,
startBlock: block.number,
lastRewardDate: block.timestamp,
finishTime: 0,
status: NodeStatus.Active,
validatorId: validatorId
}));
nodeIndex = nodes.length.sub(1);
validatorToNodeIndexes[validatorId].push(nodeIndex);
bytes32 nodeId =keccak256(abi.encodePacked(name));
nodesIPCheck[ip] =true;
nodesNameCheck[nodeId] =true;
nodesNameToIndex[nodeId] = nodeIndex;
nodeIndexes[from].isNodeExist[nodeIndex] =true;
nodeIndexes[from].numberOfNodes++;
spaceOfNodes.push(SpaceManaging({
freeSpace: constantsHolder.TOTAL_SPACE_ON_NODE(),
indexInSpaceMap: spaceToNodes[constantsHolder.TOTAL_SPACE_ON_NODE()].length
}));
spaceToNodes[constantsHolder.TOTAL_SPACE_ON_NODE()].push(nodeIndex);
numberOfActiveNodes++;
}
function_deleteNode(uint nodeIndex) private{
uint8 space = spaceOfNodes[nodeIndex].freeSpace;
uint indexInArray = spaceOfNodes[nodeIndex].indexInSpaceMap;
if (indexInArray < spaceToNodes[space].length.sub(1)) {
uint shiftedIndex = spaceToNodes[space][spaceToNodes[space].length.sub(1)];
spaceToNodes[space][indexInArray] = shiftedIndex;
spaceOfNodes[shiftedIndex].indexInSpaceMap = indexInArray;
spaceToNodes[space].pop();
} else {
spaceToNodes[space].pop();
}
delete spaceOfNodes[nodeIndex].freeSpace;
delete spaceOfNodes[nodeIndex].indexInSpaceMap;
}
}
Contract Source Code
File 12 of 36: OCContext.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.6.0;/*
* @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.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (addresspayable) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytesmemory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691returnmsg.data;
}
}
Contract Source Code
File 13 of 36: OCECDSA.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.
*/libraryECDSA{
/**
* @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.
*/functionrecover(bytes32 hash, bytesmemory signature) internalpurereturns (address) {
// Check the signature lengthif (signature.length!=65) {
revert("ECDSA: invalid signature length");
}
// Divide the signature in r, s and v variablesbytes32 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-assemblyassembly {
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 addressaddress 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}.
*/functiontoEthSignedMessageHash(bytes32 hash) internalpurereturns (bytes32) {
// 32 is the length in bytes of hash,// enforced by the type signature abovereturnkeccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
}
Contract Source Code
File 14 of 36: OCIERC1820Registry.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.6.0;/**
* @dev Interface of the global ERC1820 Registry, as defined in the
* https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register
* implementers for interfaces in this registry, as well as query support.
*
* Implementers may be shared by multiple accounts, and can also implement more
* than a single interface for each account. Contracts can implement interfaces
* for themselves, but externally-owned accounts (EOA) must delegate this to a
* contract.
*
* {IERC165} interfaces can also be queried via the registry.
*
* For an in-depth explanation and source code analysis, see the EIP text.
*/interfaceIERC1820Registry{
/**
* @dev Sets `newManager` as the manager for `account`. A manager of an
* account is able to set interface implementers for it.
*
* By default, each account is its own manager. Passing a value of `0x0` in
* `newManager` will reset the manager to this initial state.
*
* Emits a {ManagerChanged} event.
*
* Requirements:
*
* - the caller must be the current manager for `account`.
*/functionsetManager(address account, address newManager) external;
/**
* @dev Returns the manager for `account`.
*
* See {setManager}.
*/functiongetManager(address account) externalviewreturns (address);
/**
* @dev Sets the `implementer` contract as ``account``'s implementer for
* `interfaceHash`.
*
* `account` being the zero address is an alias for the caller's address.
* The zero address can also be used in `implementer` to remove an old one.
*
* See {interfaceHash} to learn how these are created.
*
* Emits an {InterfaceImplementerSet} event.
*
* Requirements:
*
* - the caller must be the current manager for `account`.
* - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not
* end in 28 zeroes).
* - `implementer` must implement {IERC1820Implementer} and return true when
* queried for support, unless `implementer` is the caller. See
* {IERC1820Implementer-canImplementInterfaceForAddress}.
*/functionsetInterfaceImplementer(address account, bytes32 interfaceHash, address implementer) external;
/**
* @dev Returns the implementer of `interfaceHash` for `account`. If no such
* implementer is registered, returns the zero address.
*
* If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28
* zeroes), `account` will be queried for support of it.
*
* `account` being the zero address is an alias for the caller's address.
*/functiongetInterfaceImplementer(address account, bytes32 interfaceHash) externalviewreturns (address);
/**
* @dev Returns the interface hash for an `interfaceName`, as defined in the
* corresponding
* https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].
*/functioninterfaceHash(stringcalldata interfaceName) externalpurereturns (bytes32);
/**
* @notice Updates the cache with whether the contract implements an ERC165 interface or not.
* @param account Address of the contract for which to update the cache.
* @param interfaceId ERC165 interface for which to update the cache.
*/functionupdateERC165Cache(address account, bytes4 interfaceId) external;
/**
* @notice Checks whether a contract implements an ERC165 interface or not.
* If the result is not cached a direct lookup on the contract address is performed.
* If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling
* {updateERC165Cache} with the contract address.
* @param account Address of the contract to check.
* @param interfaceId ERC165 interface to check.
* @return True if `account` implements `interfaceId`, false otherwise.
*/functionimplementsERC165Interface(address account, bytes4 interfaceId) externalviewreturns (bool);
/**
* @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.
* @param account Address of the contract to check.
* @param interfaceId ERC165 interface to check.
* @return True if `account` implements `interfaceId`, false otherwise.
*/functionimplementsERC165InterfaceNoCache(address account, bytes4 interfaceId) externalviewreturns (bool);
eventInterfaceImplementerSet(addressindexed account, bytes32indexed interfaceHash, addressindexed implementer);
eventManagerChanged(addressindexed account, addressindexed newManager);
}
Contract Source Code
File 15 of 36: OCIERC20.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.6.0;/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/interfaceIERC20{
/**
* @dev Returns the amount of tokens in existence.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/functionbalanceOf(address account) externalviewreturns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransfer(address recipient, uint256 amount) externalreturns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/functionallowance(address owner, address spender) externalviewreturns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/functionapprove(address spender, uint256 amount) externalreturns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransferFrom(address sender, address recipient, uint256 amount) externalreturns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/eventApproval(addressindexed owner, addressindexed spender, uint256 value);
}
Contract Source Code
File 16 of 36: OCIERC777.sol
// SPDX-License-Identifier: MITpragmasolidity ^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}.
*/interfaceIERC777{
/**
* @dev Returns the name of the token.
*/functionname() externalviewreturns (stringmemory);
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/functionsymbol() externalviewreturns (stringmemory);
/**
* @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.
*/functiongranularity() externalviewreturns (uint256);
/**
* @dev Returns the amount of tokens in existence.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns the amount of tokens owned by an account (`owner`).
*/functionbalanceOf(address owner) externalviewreturns (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.
*/functionsend(address recipient, uint256 amount, bytescalldata 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.
*/functionburn(uint256 amount, bytescalldata 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}.
*/functionisOperatorFor(address operator, address tokenHolder) externalviewreturns (bool);
/**
* @dev Make an account an operator of the caller.
*
* See {isOperatorFor}.
*
* Emits an {AuthorizedOperator} event.
*
* Requirements
*
* - `operator` cannot be calling address.
*/functionauthorizeOperator(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.
*/functionrevokeOperator(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.
*/functiondefaultOperators() externalviewreturns (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.
*/functionoperatorSend(address sender,
address recipient,
uint256 amount,
bytescalldata data,
bytescalldata 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`.
*/functionoperatorBurn(address account,
uint256 amount,
bytescalldata data,
bytescalldata operatorData
) external;
eventSent(addressindexed operator,
addressindexedfrom,
addressindexed to,
uint256 amount,
bytes data,
bytes operatorData
);
eventMinted(addressindexed operator, addressindexed to, uint256 amount, bytes data, bytes operatorData);
eventBurned(addressindexed operator, addressindexedfrom, uint256 amount, bytes data, bytes operatorData);
eventAuthorizedOperator(addressindexed operator, addressindexed tokenHolder);
eventRevokedOperator(addressindexed operator, addressindexed tokenHolder);
}
Contract Source Code
File 17 of 36: OCIERC777Recipient.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.6.0;/**
* @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.
*
* Accounts can be notified of {IERC777} tokens being sent to them by having a
* contract implement this interface (contract holders can be their own
* implementer) and registering it on the
* https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].
*
* See {IERC1820Registry} and {ERC1820Implementer}.
*/interfaceIERC777Recipient{
/**
* @dev Called by an {IERC777} token contract whenever tokens are being
* moved or created into a registered account (`to`). The type of operation
* is conveyed by `from` being the zero address or not.
*
* This call occurs _after_ the token contract's state is updated, so
* {IERC777-balanceOf}, etc., can be used to query the post-operation state.
*
* This function may revert to prevent the operation from being executed.
*/functiontokensReceived(address operator,
addressfrom,
address to,
uint256 amount,
bytescalldata userData,
bytescalldata operatorData
) external;
}
Contract Source Code
File 18 of 36: OCIERC777Sender.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.6.0;/**
* @dev Interface of the ERC777TokensSender standard as defined in the EIP.
*
* {IERC777} Token holders can be notified of operations performed on their
* tokens by having a contract implement this interface (contract holders can be
* their own implementer) and registering it on the
* https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].
*
* See {IERC1820Registry} and {ERC1820Implementer}.
*/interfaceIERC777Sender{
/**
* @dev Called by an {IERC777} token contract whenever a registered holder's
* (`from`) tokens are about to be moved or destroyed. The type of operation
* is conveyed by `to` being the zero address or not.
*
* This call occurs _before_ the token contract's state is updated, so
* {IERC777-balanceOf}, etc., can be used to query the pre-operation state.
*
* This function may revert to prevent the operation from being executed.
*/functiontokensToSend(address operator,
addressfrom,
address to,
uint256 amount,
bytescalldata userData,
bytescalldata operatorData
) external;
}
Contract Source Code
File 19 of 36: OCReentrancyGuard.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.6.0;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/contractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant _NOT_ENTERED =1;
uint256privateconstant _ENTERED =2;
uint256private _status;
constructor () internal{
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
// On the first call to nonReentrant, _notEntered will be truerequire(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
Contract Source Code
File 20 of 36: OCSafeCast.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.6.0;/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 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} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/librarySafeCast{
/**
* @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
*/functiontoUint128(uint256 value) internalpurereturns (uint128) {
require(value <2**128, "SafeCast: value doesn\'t fit in 128 bits");
returnuint128(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
*/functiontoUint64(uint256 value) internalpurereturns (uint64) {
require(value <2**64, "SafeCast: value doesn\'t fit in 64 bits");
returnuint64(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
*/functiontoUint32(uint256 value) internalpurereturns (uint32) {
require(value <2**32, "SafeCast: value doesn\'t fit in 32 bits");
returnuint32(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
*/functiontoUint16(uint256 value) internalpurereturns (uint16) {
require(value <2**16, "SafeCast: value doesn\'t fit in 16 bits");
returnuint16(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.
*/functiontoUint8(uint256 value) internalpurereturns (uint8) {
require(value <2**8, "SafeCast: value doesn\'t fit in 8 bits");
returnuint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/functiontoUint256(int256 value) internalpurereturns (uint256) {
require(value >=0, "SafeCast: value must be positive");
returnuint256(value);
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/functiontoInt128(int256 value) internalpurereturns (int128) {
require(value >=-2**127&& value <2**127, "SafeCast: value doesn\'t fit in 128 bits");
returnint128(value);
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/functiontoInt64(int256 value) internalpurereturns (int64) {
require(value >=-2**63&& value <2**63, "SafeCast: value doesn\'t fit in 64 bits");
returnint64(value);
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/functiontoInt32(int256 value) internalpurereturns (int32) {
require(value >=-2**31&& value <2**31, "SafeCast: value doesn\'t fit in 32 bits");
returnint32(value);
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/functiontoInt16(int256 value) internalpurereturns (int16) {
require(value >=-2**15&& value <2**15, "SafeCast: value doesn\'t fit in 16 bits");
returnint16(value);
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*
* _Available since v3.1._
*/functiontoInt8(int256 value) internalpurereturns (int8) {
require(value >=-2**7&& value <2**7, "SafeCast: value doesn\'t fit in 8 bits");
returnint8(value);
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/functiontoInt256(uint256 value) internalpurereturns (int256) {
require(value <2**255, "SafeCast: value doesn't fit in an int256");
returnint256(value);
}
}
Contract Source Code
File 21 of 36: OCSafeMath.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.
*/librarySafeMath{
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/functionadd(uint256 a, uint256 b) internalpurereturns (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.
*/functionsub(uint256 a, uint256 b) internalpurereturns (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.
*/functionsub(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (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.
*/functionmul(uint256 a, uint256 b) internalpurereturns (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/522if (a ==0) {
return0;
}
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.
*/functiondiv(uint256 a, uint256 b) internalpurereturns (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.
*/functiondiv(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
require(b >0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't holdreturn 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.
*/functionmod(uint256 a, uint256 b) internalpurereturns (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.
*/functionmod(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
require(b !=0, errorMessage);
return a % b;
}
}
Contract Source Code
File 22 of 36: OEPAccessControl.sol
pragmasolidity ^0.6.0;import"./OEPEnumerableSet.sol";
import"./OEPAddress.sol";
import"./OEPContext.sol";
import"./OEPInitializable.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}.
*/abstractcontractAccessControlUpgradeSafeisInitializable, ContextUpgradeSafe{
function__AccessControl_init() internalinitializer{
__Context_init_unchained();
__AccessControl_init_unchained();
}
function__AccessControl_init_unchained() internalinitializer{
}
usingEnumerableSetforEnumerableSet.AddressSet;
usingAddressforaddress;
structRoleData {
EnumerableSet.AddressSet members;
bytes32 adminRole;
}
mapping (bytes32=> RoleData) private _roles;
bytes32publicconstant 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}.
*/eventRoleGranted(bytes32indexed role, addressindexed account, addressindexed 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`)
*/eventRoleRevoked(bytes32indexed role, addressindexed account, addressindexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/functionhasRole(bytes32 role, address account) publicviewreturns (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.
*/functiongetRoleMemberCount(bytes32 role) publicviewreturns (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.
*/functiongetRoleMember(bytes32 role, uint256 index) publicviewreturns (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}.
*/functiongetRoleAdmin(bytes32 role) publicviewreturns (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.
*/functiongrantRole(bytes32 role, address account) publicvirtual{
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.
*/functionrevokeRole(bytes32 role, address account) publicvirtual{
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`.
*/functionrenounceRole(bytes32 role, address account) publicvirtual{
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) internalvirtual{
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*/function_setRoleAdmin(bytes32 role, bytes32 adminRole) internalvirtual{
_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;
}
Contract Source Code
File 23 of 36: OEPAddress.sol
pragmasolidity ^0.6.2;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @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
* ====
*/functionisContract(address account) internalviewreturns (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-assemblyassembly { 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].
*/functionsendValue(addresspayable 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");
}
}
Contract Source Code
File 24 of 36: OEPContext.sol
pragmasolidity ^0.6.0;import"./OEPInitializable.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.
*/contractContextUpgradeSafeisInitializable{
// Empty internal constructor, to prevent people from mistakenly deploying// an instance of this contract, which should be used via inheritance.function__Context_init() internalinitializer{
__Context_init_unchained();
}
function__Context_init_unchained() internalinitializer{
}
function_msgSender() internalviewvirtualreturns (addresspayable) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytesmemory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691returnmsg.data;
}
uint256[50] private __gap;
}
Contract Source Code
File 25 of 36: OEPEnumerableSet.sol
pragmasolidity ^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.
*/libraryEnumerableSet{
// 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.structSet {
// Storage of set valuesbytes32[] _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) privatereturns (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;
returntrue;
} else {
returnfalse;
}
}
/**
* @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) privatereturns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slotuint256 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 slotdelete set._indexes[value];
returntrue;
} else {
returnfalse;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/function_contains(Set storage set, bytes32 value) privateviewreturns (bool) {
return set._indexes[value] !=0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/function_length(Set storage set) privateviewreturns (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) privateviewreturns (bytes32) {
require(set._values.length> index, "EnumerableSet: index out of bounds");
return set._values[index];
}
// AddressSetstructAddressSet {
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.
*/functionadd(AddressSet storage set, address value) internalreturns (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.
*/functionremove(AddressSet storage set, address value) internalreturns (bool) {
return _remove(set._inner, bytes32(uint256(value)));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/functioncontains(AddressSet storage set, address value) internalviewreturns (bool) {
return _contains(set._inner, bytes32(uint256(value)));
}
/**
* @dev Returns the number of values in the set. O(1).
*/functionlength(AddressSet storage set) internalviewreturns (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}.
*/functionat(AddressSet storage set, uint256 index) internalviewreturns (address) {
returnaddress(uint256(_at(set._inner, index)));
}
// UintSetstructUintSet {
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.
*/functionadd(UintSet storage set, uint256 value) internalreturns (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.
*/functionremove(UintSet storage set, uint256 value) internalreturns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/functioncontains(UintSet storage set, uint256 value) internalviewreturns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/functionlength(UintSet storage set) internalviewreturns (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}.
*/functionat(UintSet storage set, uint256 index) internalviewreturns (uint256) {
returnuint256(_at(set._inner, index));
}
}
Contract Source Code
File 26 of 36: OEPInitializable.sol
pragmasolidity >=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.
*/contractInitializable{
/**
* @dev Indicates that the contract has been initialized.
*/boolprivate initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/boolprivate initializing;
/**
* @dev Modifier to use in the initializer function of a contract.
*/modifierinitializer() {
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 constructorfunctionisConstructor() privateviewreturns (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.addressself=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;
}
Contract Source Code
File 27 of 36: OEPOwnable.sol
pragmasolidity ^0.6.0;import"./OEPContext.sol";
import"./OEPInitializable.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.
*/contractOwnableUpgradeSafeisInitializable, ContextUpgradeSafe{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/function__Ownable_init() internalinitializer{
__Context_init_unchained();
__Ownable_init_unchained();
}
function__Ownable_init_unchained() internalinitializer{
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewreturns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
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.
*/functionrenounceOwnership() publicvirtualonlyOwner{
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.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
uint256[49] private __gap;
}
Contract Source Code
File 28 of 36: PartialDifferences.sol
// 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/>.
*/pragmasolidity 0.6.10;import"./MathUtils.sol";
import"./FractionUtils.sol";
/**
* @title Partial Differences Library
* @dev This library contains functions to manage Partial Differences data
* structure. Partial Differences is an array of value differences over time.
*
* For example: assuming an array [3, 6, 3, 1, 2], partial differences can
* represent this array as [_, 3, -3, -2, 1].
*
* This data structure allows adding values on an open interval with O(1)
* complexity.
*
* For example: add +5 to [3, 6, 3, 1, 2] starting from the second element (3),
* instead of performing [3, 6, 3+5, 1+5, 2+5] partial differences allows
* performing [_, 3, -3+5, -2, 1]. The original array can be restored by
* adding values from partial differences.
*/libraryPartialDifferences{
usingSafeMathforuint;
usingMathUtilsforuint;
structSequence {
// month => diffmapping (uint=>uint) addDiff;
// month => diffmapping (uint=>uint) subtractDiff;
// month => valuemapping (uint=>uint) value;
uint firstUnprocessedMonth;
uint lastChangedMonth;
}
structValue {
// month => diffmapping (uint=>uint) addDiff;
// month => diffmapping (uint=>uint) subtractDiff;
uint value;
uint firstUnprocessedMonth;
uint lastChangedMonth;
}
// functions for sequencefunctionaddToSequence(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;
}
}
functionsubtractFromSequence(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;
}
}
functiongetAndUpdateValueInSequence(Sequence storage sequence, uint month) internalreturns (uint) {
if (sequence.firstUnprocessedMonth ==0) {
return0;
}
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];
}
functionreduceSequence(
Sequence storage sequence,
FractionUtils.Fraction memory reducingCoefficient,
uint month) internal{
require(month.add(1) >= sequence.firstUnprocessedMonth, "Can't reduce value in the past");
require(
reducingCoefficient.numerator <= reducingCoefficient.denominator,
"Increasing of values is not implemented");
if (sequence.firstUnprocessedMonth ==0) {
return;
}
uint value = getAndUpdateValueInSequence(sequence, month);
if (value.approximatelyEqual(0)) {
return;
}
sequence.value[month] = sequence.value[month]
.mul(reducingCoefficient.numerator)
.div(reducingCoefficient.denominator);
for (uint i = month.add(1); i <= sequence.lastChangedMonth; ++i) {
sequence.subtractDiff[i] = sequence.subtractDiff[i]
.mul(reducingCoefficient.numerator)
.div(reducingCoefficient.denominator);
}
}
// functions for valuefunctionaddToValue(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);
}
}
functionsubtractFromValue(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);
}
}
functiongetAndUpdateValue(Value storage sequence, uint month) internalreturns (uint) {
require(
month.add(1) >= sequence.firstUnprocessedMonth,
"Cannot calculate value in the past");
if (sequence.firstUnprocessedMonth ==0) {
return0;
}
if (sequence.firstUnprocessedMonth <= month) {
for (uint i = sequence.firstUnprocessedMonth; i <= month; ++i) {
uint newValue = sequence.value.add(sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]);
if (sequence.value!= newValue) {
sequence.value= newValue;
}
if (sequence.addDiff[i] >0) {
delete sequence.addDiff[i];
}
if (sequence.subtractDiff[i] >0) {
delete sequence.subtractDiff[i];
}
}
sequence.firstUnprocessedMonth = month.add(1);
}
return sequence.value;
}
functionreduceValue(
Value storage sequence,
uint amount,
uint month)
internalreturns (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;
}
functionreduceValueByCoefficient(
Value storage sequence,
FractionUtils.Fraction memory reducingCoefficient,
uint month)
internal{
reduceValueByCoefficientAndUpdateSumIfNeeded(
sequence,
sequence,
reducingCoefficient,
month,
false);
}
functionreduceValueByCoefficientAndUpdateSum(
Value storage sequence,
Value storage sumSequence,
FractionUtils.Fraction memory reducingCoefficient,
uint month) internal{
reduceValueByCoefficientAndUpdateSumIfNeeded(
sequence,
sumSequence,
reducingCoefficient,
month,
true);
}
functionreduceValueByCoefficientAndUpdateSumIfNeeded(
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;
}
}
functionclear(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;
}
}
}
Contract Source Code
File 29 of 36: Permissions.sol
// 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/>.
*/pragmasolidity 0.6.10;import"./OCSafeMath.sol";
import"./OEPAccessControl.sol";
import"./ContractManager.sol";
/**
* @title Permissions - connected module for Upgradeable approach, knows ContractManager
* @author Artem Payvin
*/contractPermissionsisAccessControlUpgradeSafe{
usingSafeMathforuint;
usingAddressforaddress;
ContractManager public contractManager;
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
require(_isOwner(), "Caller is not the owner");
_;
}
modifieronlyAdmin() {
require(_isAdmin(msg.sender), "Caller is not an admin");
_;
}
/**
* @dev allow - throws if called by any account and contract other than the owner
* or `contractName` contract
* @param contractName - human readable name of contract
*/modifierallow(stringmemory contractName) {
require(
contractManager.contracts(keccak256(abi.encodePacked(contractName))) ==msg.sender|| _isOwner(),
"Message sender is invalid");
_;
}
modifierallowTwo(stringmemory contractName1, stringmemory contractName2) {
require(
contractManager.contracts(keccak256(abi.encodePacked(contractName1))) ==msg.sender||
contractManager.contracts(keccak256(abi.encodePacked(contractName2))) ==msg.sender||
_isOwner(),
"Message sender is invalid");
_;
}
modifierallowThree(stringmemory contractName1, stringmemory contractName2, stringmemory contractName3) {
require(
contractManager.contracts(keccak256(abi.encodePacked(contractName1))) ==msg.sender||
contractManager.contracts(keccak256(abi.encodePacked(contractName2))) ==msg.sender||
contractManager.contracts(keccak256(abi.encodePacked(contractName3))) ==msg.sender||
_isOwner(),
"Message sender is invalid");
_;
}
functioninitialize(address contractManagerAddress) publicvirtualinitializer{
AccessControlUpgradeSafe.__AccessControl_init();
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setContractManager(contractManagerAddress);
}
function_isOwner() internalviewreturns (bool) {
return hasRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function_isAdmin(address account) internalviewreturns (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);
}
}
Contract Source Code
File 30 of 36: Punisher.sol
// 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/>.
*/pragmasolidity 0.6.10;import"./OCSafeMath.sol";
import"./Permissions.sol";
import"./ILocker.sol";
import"./ValidatorService.sol";
import"./DelegationController.sol";
/**
* @title Punisher
* @dev This contract handles all slashing and forgiving operations.
*/contractPunisherisPermissions, ILocker{
/**
* @dev Emitted when a slashing condition occurs.
*/eventSlash(uint validatorId,
uint amount
);
/**
* @dev Emitted when a forgive condition occurs.
*/eventForgive(address wallet,
uint amount
);
// holder => tokensmapping (address=>uint) private _locked;
/**
* @dev Executes slashing on a validator and its delegations by an `amount`
* of tokens. Currently, SkaleDKG is the only service allowed to execute
* slashing.
*
* Emits a Slash event.
*
* @param validatorId uint validator to be slashed
* @param amount uint slashed amount
*/functionslash(uint validatorId, uint amount) externalallow("SkaleDKG") {
ValidatorService validatorService = ValidatorService(contractManager.getContract("ValidatorService"));
DelegationController delegationController = DelegationController(
contractManager.getContract("DelegationController"));
require(validatorService.validatorExists(validatorId), "Validator does not exist");
delegationController.confiscate(validatorId, amount);
emit Slash(validatorId, amount);
}
/**
* @dev Allows the Owner to forgive a slashing condition.
*
* Emits a Forgive event.
*
* @param holder address of the slashed
* @param amount uint amount to be forgiven
*/functionforgive(address holder, uint amount) externalonlyAdmin{
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
*/functiongetAndUpdateLockedAmount(address wallet) externaloverridereturns (uint) {
return _getAndUpdateLockedAmount(wallet);
}
/**
* @dev See ILocker-getAndUpdateForbiddenForDelegationAmount
*/functiongetAndUpdateForbiddenForDelegationAmount(address wallet) externaloverridereturns (uint) {
return _getAndUpdateLockedAmount(wallet);
}
functionhandleSlash(address holder, uint amount) externalallow("DelegationController") {
_locked[holder] = _locked[holder].add(amount);
}
functioninitialize(address contractManagerAddress) publicoverrideinitializer{
Permissions.initialize(contractManagerAddress);
}
// privatefunction_getAndUpdateLockedAmount(address wallet) privatereturns (uint) {
DelegationController delegationController = DelegationController(
contractManager.getContract("DelegationController"));
delegationController.processAllSlashes(wallet);
return _locked[wallet];
}
}
Contract Source Code
File 31 of 36: SkaleToken.sol
// SPDX-License-Identifier: AGPL-3.0-only/*
SkaleToken.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/>.
*/pragmasolidity 0.6.10;import"./OCSafeMath.sol";
import"./OCReentrancyGuard.sol";
import"./ERC777.sol";
import"./Permissions.sol";
import"./IDelegatableToken.sol";
import"./Punisher.sol";
import"./TokenState.sol";
/**
* @title SkaleToken is ERC777 Token implementation, also this contract in skale
* manager system
*/contractSkaleTokenisERC777, Permissions, ReentrancyGuard, IDelegatableToken{
usingSafeMathforuint;
stringpublicconstant NAME ="SKALE";
stringpublicconstant SYMBOL ="SKL";
uintpublicconstant DECIMALS =18;
uintpublicconstant CAP =7*1e9* (10** DECIMALS); // the maximum amount of tokens that can ever be createdconstructor(address contractsAddress, address[] memory defOps) publicERC777("SKALE", "SKL", defOps)
{
Permissions.initialize(contractsAddress);
}
/**
* @dev mint - create some amount of token and transfer it to the specified address
* @param account - address where some amount of token would be created
* @param amount - amount of tokens to mine
* @param userData bytes extra information provided by the token holder (if any)
* @param operatorData bytes extra information provided by the operator (if any)
* @return returns success of function call.
*/functionmint(address account,
uint256 amount,
bytescalldata userData,
bytescalldata operatorData
)
externalallow("SkaleManager")
//onlyAuthorizedreturns (bool)
{
require(amount <= CAP.sub(totalSupply()), "Amount is too big");
_mint(
account,
amount,
userData,
operatorData
);
returntrue;
}
functiongetAndUpdateDelegatedAmount(address wallet) externaloverridereturns (uint) {
return DelegationController(contractManager.getContract("DelegationController"))
.getAndUpdateDelegatedAmount(wallet);
}
functiongetAndUpdateSlashedAmount(address wallet) externaloverridereturns (uint) {
return Punisher(contractManager.getContract("Punisher")).getAndUpdateLockedAmount(wallet);
}
functiongetAndUpdateLockedAmount(address wallet) publicoverridereturns (uint) {
return TokenState(contractManager.getContract("TokenState")).getAndUpdateLockedAmount(wallet);
}
// internalfunction_beforeTokenTransfer(address, // operatoraddressfrom,
address, // touint256 tokenId)
internaloverride{
uint locked = getAndUpdateLockedAmount(from);
if (locked >0) {
require(balanceOf(from) >= locked.add(tokenId), "Token should be unlocked for transferring");
}
}
function_callTokensToSend(address operator,
addressfrom,
address to,
uint256 amount,
bytesmemory userData,
bytesmemory operatorData
) internaloverridenonReentrant{
super._callTokensToSend(operator, from, to, amount, userData, operatorData);
}
function_callTokensReceived(address operator,
addressfrom,
address to,
uint256 amount,
bytesmemory userData,
bytesmemory operatorData,
bool requireReceptionAck
) internaloverridenonReentrant{
super._callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck);
}
// we have to override _msgData() and _msgSender() functions because of collision in Context and ContextUpgradeSafefunction_msgData() internalviewoverride(Context, ContextUpgradeSafe) returns (bytesmemory) {
return Context._msgData();
}
function_msgSender() internalviewoverride(Context, ContextUpgradeSafe) returns (addresspayable) {
return Context._msgSender();
}
}
Contract Source Code
File 32 of 36: StringUtils.sol
// 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/>.
*/pragmasolidity 0.6.10;import"./OCSafeMath.sol";
libraryStringUtils{
usingSafeMathforuint;
functionstrConcat(stringmemory a, stringmemory b) internalpurereturns (stringmemory) {
bytesmemory _ba =bytes(a);
bytesmemory _bb =bytes(b);
stringmemory ab =newstring(_ba.length.add(_bb.length));
bytesmemory 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];
}
returnstring(strBytes);
}
functionuint2str(uint i) internalpurereturns (stringmemory) {
if (i ==0) {
return"0";
}
uint j = i;
uint _i = i;
uint len;
while (j !=0) {
len++;
j /=10;
}
bytesmemory bstr =newbytes(len);
uint k = len.sub(1);
while (_i !=0) {
bstr[k--] =byte(uint8(48+ _i %10));
_i /=10;
}
returnstring(bstr);
}
}
Contract Source Code
File 33 of 36: TimeHelpers.sol
// 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/>.
*/pragmasolidity 0.6.10;import"./OCSafeMath.sol";
import"./BokkyPooBahsDateTimeLibrary.sol";
/**
* @title TimeHelpers
* @dev The contract performs time operations.
*
* These functions are used to calculate monthly and Proof of Use epochs.
*/contractTimeHelpers{
usingSafeMathforuint;
uintconstantprivate _ZERO_YEAR =2020;
functioncalculateProofOfUseLockEndTime(uint month, uint lockUpPeriodDays) externalviewreturns (uint timestamp) {
timestamp = BokkyPooBahsDateTimeLibrary.addDays(monthToTimestamp(month), lockUpPeriodDays);
}
functionaddMonths(uint fromTimestamp, uint n) externalpurereturns (uint) {
return BokkyPooBahsDateTimeLibrary.addMonths(fromTimestamp, n);
}
functiongetCurrentMonth() externalviewvirtualreturns (uint) {
return timestampToMonth(now);
}
functiontimestampToMonth(uint timestamp) publicviewvirtualreturns (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;
}
functionmonthToTimestamp(uint month) publicviewvirtualreturns (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);
}
}
Contract Source Code
File 34 of 36: TokenLaunchLocker.sol
// 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/>.
*/pragmasolidity 0.6.10;import"./OCSafeMath.sol";
import"./Permissions.sol";
import"./ILocker.sol";
import"./ConstantsHolder.sol";
import"./MathUtils.sol";
import"./DelegationController.sol";
import"./TimeHelpers.sol";
import"./PartialDifferences.sol";
contractTokenLaunchLockerisPermissions, ILocker{
usingMathUtilsforuint;
usingPartialDifferencesforPartialDifferences.Value;
/**
* @dev Emitted when an `amount` is unlocked.
*/eventUnlocked(address holder,
uint amount
);
/**
* @dev Emitted when an `amount` is locked.
*/eventLocked(address holder,
uint amount
);
structDelegatedAmountAndMonth {
uint delegated;
uint month;
}
// holder => tokensmapping (address=>uint) private _locked;
// holder => tokensmapping (address=> PartialDifferences.Value) private _delegatedAmount;
mapping (address=> DelegatedAmountAndMonth) private _totalDelegatedAmount;
// delegationId => tokensmapping (uint=>uint) private _delegationAmount;
functionlock(address holder, uint amount) externalallow("TokenLaunchManager") {
_locked[holder] = _locked[holder].add(amount);
emit Locked(holder, amount);
}
functionhandleDelegationAdd(address holder, uint delegationId, uint amount, uint month)
externalallow("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;
}
}
}
functionhandleDelegationRemoving(address holder,
uint delegationId,
uint month)
externalallow("DelegationController")
{
if (_delegationAmount[delegationId] >0) {
if (_locked[holder] >0) {
_removeFromDelegatedAmount(holder, _delegationAmount[delegationId], month);
}
delete _delegationAmount[delegationId];
}
}
functiongetAndUpdateLockedAmount(address wallet) externaloverridereturns (uint) {
if (_locked[wallet] >0) {
DelegationController delegationController = DelegationController(
contractManager.getContract("DelegationController"));
TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers"));
ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder"));
uint currentMonth = timeHelpers.getCurrentMonth();
if (_totalDelegatedSatisfiesProofOfUserCondition(wallet) &&
timeHelpers.calculateProofOfUseLockEndTime(
_totalDelegatedAmount[wallet].month,
constantsHolder.proofOfUseLockUpPeriodDays()
) <=now) {
_unlock(wallet);
return0;
} else {
uint lockedByDelegationController = _getAndUpdateDelegatedAmount(wallet, currentMonth)
.add(delegationController.getLockedInPendingDelegations(wallet));
if (_locked[wallet] > lockedByDelegationController) {
return _locked[wallet].boundedSub(lockedByDelegationController);
} else {
return0;
}
}
} else {
return0;
}
}
functiongetAndUpdateForbiddenForDelegationAmount(address) externaloverridereturns (uint) {
return0;
}
functioninitialize(address contractManagerAddress) publicoverrideinitializer{
Permissions.initialize(contractManagerAddress);
}
// privatefunction_getAndUpdateDelegatedAmount(address holder, uint currentMonth) privatereturns (uint) {
return _delegatedAmount[holder].getAndUpdateValue(currentMonth);
}
function_addToDelegatedAmount(address holder, uint amount, uint month) private{
_delegatedAmount[holder].addToValue(amount, month);
}
function_removeFromDelegatedAmount(address holder, uint amount, uint month) private{
_delegatedAmount[holder].subtractFromValue(amount, month);
}
function_addToTotalDelegatedAmount(address holder, uint amount, uint month) private{
require(
_totalDelegatedAmount[holder].month ==0|| _totalDelegatedAmount[holder].month <= month,
"Can't add to total delegated in the past");
// do not update counter if it is big enough// because it will override month valueif (!_totalDelegatedSatisfiesProofOfUserCondition(holder)) {
_totalDelegatedAmount[holder].delegated = _totalDelegatedAmount[holder].delegated.add(amount);
_totalDelegatedAmount[holder].month = month;
}
}
function_unlock(address holder) private{
emit Unlocked(holder, _locked[holder]);
delete _locked[holder];
_deleteDelegatedAmount(holder);
_deleteTotalDelegatedAmount(holder);
}
function_deleteDelegatedAmount(address holder) private{
_delegatedAmount[holder].clear();
}
function_deleteTotalDelegatedAmount(address holder) private{
delete _totalDelegatedAmount[holder].delegated;
delete _totalDelegatedAmount[holder].month;
}
function_totalDelegatedSatisfiesProofOfUserCondition(address holder) privateviewreturns (bool) {
ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder"));
return _totalDelegatedAmount[holder].delegated.mul(100) >=
_locked[holder].mul(constantsHolder.proofOfUseDelegationPercentage());
}
}
Contract Source Code
File 35 of 36: TokenState.sol
// 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/>.
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;import"./Permissions.sol";
import"./DelegationController.sol";
import"./TimeHelpers.sol";
import"./ILocker.sol";
/**
* @title Token State
* @dev This contract manages lockers to control token transferability.
*
* See ILocker.
*/contractTokenStateisPermissions, ILocker{
/**
* @dev Emitted when a contract is added to the locker.
*/eventLockerWasAdded(string locker
);
/**
* @dev Emitted when a contract is removed from the locker.
*/eventLockerWasRemoved(string locker
);
string[] private _lockers;
/**
* @dev Return and update the total locked amount of a given `holder`.
*
* @param holder address of the token holder
* @return total locked amount
*/functiongetAndUpdateLockedAmount(address holder) externaloverridereturns (uint) {
uint locked =0;
for (uint i =0; i < _lockers.length; ++i) {
ILocker locker = ILocker(contractManager.getContract(_lockers[i]));
locked = locked.add(locker.getAndUpdateLockedAmount(holder));
}
return locked;
}
/**
* @dev Return and update the total locked and un-delegatable amount of a given `holder`.
*
* @param holder address of the token holder
* @return amount total slashed amount (non-transferable and non-delegatable)
*/functiongetAndUpdateForbiddenForDelegationAmount(address holder) externaloverridereturns (uint amount) {
uint forbidden =0;
for (uint i =0; i < _lockers.length; ++i) {
ILocker locker = ILocker(contractManager.getContract(_lockers[i]));
forbidden = forbidden.add(locker.getAndUpdateForbiddenForDelegationAmount(holder));
}
return forbidden;
}
/**
* @dev Allows the Owner to remove a contract from the locker.
*
* Emits a LockerWasRemoved event.
*
* @param locker string name of contract to remove from locker
*/functionremoveLocker(stringcalldata locker) externalonlyOwner{
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);
}
}
functioninitialize(address contractManagerAddress) publicoverrideinitializer{
Permissions.initialize(contractManagerAddress);
addLocker("DelegationController");
addLocker("Punisher");
addLocker("TokenLaunchLocker");
}
/**
* @dev Allows the Owner to add a contract to the Locker.
*
* Emits a LockerWasAdded event.
*
* @param locker string name of contract to add to locker
*/functionaddLocker(stringmemory locker) publiconlyOwner{
_lockers.push(locker);
emit LockerWasAdded(locker);
}
}
Contract Source Code
File 36 of 36: ValidatorService.sol
// 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/>.
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;import"./OCSafeMath.sol";
import"./OCECDSA.sol";
import"./Permissions.sol";
import"./ConstantsHolder.sol";
import"./DelegationController.sol";
/**
* @title ValidatorService
* @dev This contract handles all validator operations including registration,
* node management, validator-specific delegation parameters, and more.
*
* Validators register an address, and use this address to accept delegations and
* register nodes.
*
*/contractValidatorServiceisPermissions{
usingECDSAforbytes32;
structValidator {
string name;
address validatorAddress;
address requestedAddress;
string description;
uint feeRate;
uint registrationTime;
uint minimumDelegationAmount;
bool acceptNewRequests;
}
/**
* @dev Emitted when a validator registers.
*/eventValidatorRegistered(uint validatorId
);
/**
* @dev Emitted when a validator address changes.
*/eventValidatorAddressChanged(uint validatorId,
address newAddress
);
eventValidatorWasEnabled(uint validatorId
);
eventValidatorWasDisabled(uint validatorId
);
/**
* @dev Emitted when a node address is linked to a validator.
*/eventNodeAddressWasAdded(uint validatorId,
address nodeAddress
);
/**
* @dev Emitted when a node address is unlinked from a validator.
*/eventNodeAddressWasRemoved(uint validatorId,
address nodeAddress
);
mapping (uint=> Validator) public validators;
mapping (uint=>bool) private _trustedValidators;
uint[] public trustedValidatorsList;
// address => validatorIdmapping (address=>uint) private _validatorAddressToId;
// address => validatorIdmapping (address=>uint) private _nodeAddressToValidatorId;
// validatorId => nodeAddress[]mapping (uint=>address[]) private _nodeAddresses;
uintpublic numberOfValidators;
boolpublic useWhitelist;
modifiercheckValidatorExists(uint validatorId) {
require(validatorExists(validatorId), "Validator with such ID does not exist");
_;
}
/**
* @dev Creates a new validator Id.
*
* Requirements:
*
* - sender must not already have registered a validator Id.
* - fee rate must be between 0 - 1000‰. Note: per mille!
*
* Emits ValidatorRegistered event.
*
* @param name string
* @param description string
* @param feeRate uint Fee charged on delegations by the validator per mille
* @param minimumDelegationAmount uint Minimum delegation amount accepted by the validator
*/functionregisterValidator(stringcalldata name,
stringcalldata description,
uint feeRate,
uint minimumDelegationAmount
)
externalreturns (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);
}
functionenableValidator(uint validatorId) externalcheckValidatorExists(validatorId) onlyAdmin{
require(!_trustedValidators[validatorId], "Validator is already enabled");
_trustedValidators[validatorId] =true;
trustedValidatorsList.push(validatorId);
emit ValidatorWasEnabled(validatorId);
}
functiondisableValidator(uint validatorId) externalcheckValidatorExists(validatorId) onlyAdmin{
require(_trustedValidators[validatorId], "Validator is already disabled");
_trustedValidators[validatorId] =false;
uint position = _find(trustedValidatorsList, validatorId);
if (position < trustedValidatorsList.length) {
trustedValidatorsList[position] =
trustedValidatorsList[trustedValidatorsList.length.sub(1)];
}
trustedValidatorsList.pop();
emit ValidatorWasDisabled(validatorId);
}
/**
* @dev Owner can disable the validator whitelist. Once turned off the
* whitelist cannot be re-enabled.
*/functiondisableWhitelist() externalonlyOwner{
useWhitelist =false;
}
/**
* @dev Allows a validator to request a new address.
*
* Requirements:
*
* - new address must not be null
* - new address must not be already registered as a validator
*
* @param newValidatorAddress address
*/functionrequestForNewAddress(address newValidatorAddress) external{
require(newValidatorAddress !=address(0), "New address cannot be null");
require(_validatorAddressToId[newValidatorAddress] ==0, "Address already registered");
// check Validator Exist inside getValidatorIduint validatorId = getValidatorId(msg.sender);
validators[validatorId].requestedAddress = newValidatorAddress;
}
functionconfirmNewAddress(uint validatorId)
externalcheckValidatorExists(validatorId)
{
require(
getValidator(validatorId).requestedAddress ==msg.sender,
"The validator address cannot be changed because it is not the actual owner"
);
delete validators[validatorId].requestedAddress;
_setValidatorAddress(validatorId, msg.sender);
emit ValidatorAddressChanged(validatorId, validators[validatorId].validatorAddress);
}
/**
* @dev Links a given node address.
*
* Requirements:
*
* - the given signature must be valid.
* - the address must not be assigned to a validator.
*
* Emits NodeAddressWasAdded event.
*
* @param nodeAddress address
* @param sig bytes signature of validator Id by node operator.
*/functionlinkNodeAddress(address nodeAddress, bytescalldata sig) external{
// check Validator Exist inside getValidatorIduint validatorId = getValidatorId(msg.sender);
require(
keccak256(abi.encodePacked(validatorId)).toEthSignedMessageHash().recover(sig) == nodeAddress,
"Signature is not pass"
);
require(_validatorAddressToId[nodeAddress] ==0, "Node address is a validator");
_addNodeAddress(validatorId, nodeAddress);
emit NodeAddressWasAdded(validatorId, nodeAddress);
}
/**
* @dev Unlinks a given node address from a validator.
*
* Emits NodeAddressWasRemoved event.
*
* @param nodeAddress address
*/functionunlinkNodeAddress(address nodeAddress) external{
// check Validator Exist inside getValidatorIduint validatorId = getValidatorId(msg.sender);
_removeNodeAddress(validatorId, nodeAddress);
emit NodeAddressWasRemoved(validatorId, nodeAddress);
}
functionsetValidatorMDA(uint minimumDelegationAmount) external{
// check Validator Exist inside getValidatorIduint validatorId = getValidatorId(msg.sender);
validators[validatorId].minimumDelegationAmount = minimumDelegationAmount;
}
/**
* @dev Allows a validator to set a new validator name.
*
* @param newName string
*/functionsetValidatorName(stringcalldata newName) external{
// check Validator Exist inside getValidatorIduint validatorId = getValidatorId(msg.sender);
validators[validatorId].name= newName;
}
/**
* @dev Allows a validator to set a new validator description.
*
* @param newDescription string
*/functionsetValidatorDescription(stringcalldata newDescription) external{
// check Validator Exist inside getValidatorIduint validatorId = getValidatorId(msg.sender);
validators[validatorId].description = newDescription;
}
/**
* @dev Allows a validator to start accepting new delegation requests.
*
* Requirements:
*
* - validator must not have already enabled accepting new requests
*/functionstartAcceptingNewRequests() external{
// check Validator Exist inside getValidatorIduint validatorId = getValidatorId(msg.sender);
require(!isAcceptingNewRequests(validatorId), "Accepting request is already enabled");
validators[validatorId].acceptNewRequests =true;
}
/**
* @dev Allows a validator to stop accepting new delegation requests.
*
* Requirements:
*
* - validator must not have already stopped accepting new requests
*/functionstopAcceptingNewRequests() external{
// check Validator Exist inside getValidatorIduint validatorId = getValidatorId(msg.sender);
require(isAcceptingNewRequests(validatorId), "Accepting request is already disabled");
validators[validatorId].acceptNewRequests =false;
}
/**
* @dev Returns the amount of validator bond.
*
* @param validatorId uint ID of validator to return the amount of locked funds
* @return bondAmount uint the amount of self-delegated funds by the validator
*/functiongetAndUpdateBondAmount(uint validatorId)
externalreturns (uint)
{
DelegationController delegationController = DelegationController(
contractManager.getContract("DelegationController")
);
return delegationController.getAndUpdateDelegatedByHolderToValidatorNow(
getValidator(validatorId).validatorAddress,
validatorId
);
}
functiongetMyNodesAddresses() externalviewreturns (address[] memory) {
return getNodeAddresses(getValidatorId(msg.sender));
}
/**
* @dev Returns a list of trusted validators.
*
* @return uint[] trusted validators
*/functiongetTrustedValidators() externalviewreturns (uint[] memory) {
return trustedValidatorsList;
}
functioncheckMinimumDelegation(uint validatorId, uint amount)
externalviewcheckValidatorExists(validatorId)
allow("DelegationController")
returns (bool)
{
return validators[validatorId].minimumDelegationAmount <= amount ? true : false;
}
functioncheckValidatorAddressToId(address validatorAddress, uint validatorId)
externalviewreturns (bool)
{
return getValidatorId(validatorAddress) == validatorId ? true : false;
}
functiongetValidatorIdByNodeAddress(address nodeAddress) externalviewreturns (uint validatorId) {
validatorId = _nodeAddressToValidatorId[nodeAddress];
require(validatorId !=0, "Node address is not assigned to a validator");
}
functionisAuthorizedValidator(uint validatorId) externalviewcheckValidatorExists(validatorId) returns (bool) {
return _trustedValidators[validatorId] ||!useWhitelist;
}
functioninitialize(address contractManagerAddress) publicoverrideinitializer{
Permissions.initialize(contractManagerAddress);
useWhitelist =true;
}
functiongetNodeAddresses(uint validatorId) publicviewreturns (address[] memory) {
return _nodeAddresses[validatorId];
}
functionvalidatorExists(uint validatorId) publicviewreturns (bool) {
return validatorId <= numberOfValidators && validatorId !=0;
}
functionvalidatorAddressExists(address validatorAddress) publicviewreturns (bool) {
return _validatorAddressToId[validatorAddress] !=0;
}
functioncheckIfValidatorAddressExists(address validatorAddress) publicview{
require(validatorAddressExists(validatorAddress), "Validator with given address does not exist");
}
functiongetValidator(uint validatorId) publicviewcheckValidatorExists(validatorId) returns (Validator memory) {
return validators[validatorId];
}
functiongetValidatorId(address validatorAddress) publicviewreturns (uint) {
checkIfValidatorAddressExists(validatorAddress);
return _validatorAddressToId[validatorAddress];
}
functionisAcceptingNewRequests(uint validatorId) publicviewcheckValidatorExists(validatorId) returns (bool) {
return validators[validatorId].acceptNewRequests;
}
// privatefunction_setValidatorAddress(uint validatorId, address validatorAddress) private{
if (_validatorAddressToId[validatorAddress] == validatorId) {
return;
}
require(_validatorAddressToId[validatorAddress] ==0, "Address is in use by another validator");
address oldAddress = validators[validatorId].validatorAddress;
delete _validatorAddressToId[oldAddress];
_nodeAddressToValidatorId[validatorAddress] = validatorId;
validators[validatorId].validatorAddress = validatorAddress;
_validatorAddressToId[validatorAddress] = validatorId;
}
function_addNodeAddress(uint validatorId, address nodeAddress) private{
if (_nodeAddressToValidatorId[nodeAddress] == validatorId) {
return;
}
require(_nodeAddressToValidatorId[nodeAddress] ==0, "Validator cannot override node address");
_nodeAddressToValidatorId[nodeAddress] = validatorId;
_nodeAddresses[validatorId].push(nodeAddress);
}
function_removeNodeAddress(uint validatorId, address nodeAddress) private{
require(_nodeAddressToValidatorId[nodeAddress] == validatorId,
"Validator does not have permissions to unlink node");
delete _nodeAddressToValidatorId[nodeAddress];
for (uint i =0; i < _nodeAddresses[validatorId].length; ++i) {
if (_nodeAddresses[validatorId][i] == nodeAddress) {
if (i +1< _nodeAddresses[validatorId].length) {
_nodeAddresses[validatorId][i] =
_nodeAddresses[validatorId][_nodeAddresses[validatorId].length.sub(1)];
}
delete _nodeAddresses[validatorId][_nodeAddresses[validatorId].length.sub(1)];
_nodeAddresses[validatorId].pop();
break;
}
}
}
function_find(uint[] memory array, uint index) privatepurereturns (uint) {
uint i;
for (i =0; i < array.length; i++) {
if (array[i] == index) {
return i;
}
}
return array.length;
}
}