Transaction Hash:
Block:
19723414 at Apr-24-2024 06:20:23 AM +UTC
Transaction Fee:
0.000921418578095134 ETH
$2.87
Gas Used:
109,298 Gas / 8.430333383 Gwei
Emitted Events:
329 |
SkaleToken.Sent( operator=[Sender] 0x04956caa50920968990f68e195be59ce511a72bb, from=[Sender] 0x04956caa50920968990f68e195be59ce511a72bb, to=0x14f12aEeD4e904314C66BB1aA686A40B6DC6F89e, amount=10000000000000000000000, data=0x, operatorData=0x )
|
330 |
SkaleToken.Transfer( from=[Sender] 0x04956caa50920968990f68e195be59ce511a72bb, to=0x14f12aEeD4e904314C66BB1aA686A40B6DC6F89e, value=10000000000000000000000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x00c83aeC...80501a7A7 | |||||
0x04956cAa...E511a72BB |
0.099995434549745764 Eth
Nonce: 105
|
0.09907401597165063 Eth
Nonce: 106
| 0.000921418578095134 | ||
0x1f9090aa...8e676c326
Miner
| 5.268321332831500925 Eth | 5.268322357277938793 Eth | 0.000001024446437868 |
Execution Trace
SkaleToken.transfer( recipient=0x14f12aEeD4e904314C66BB1aA686A40B6DC6F89e, amount=10000000000000000000000 ) => ( True )
-
ERC1820Registry.getInterfaceImplementer( _addr=0x04956cAa50920968990f68e195bE59CE511a72BB, _interfaceHash=29DDB589B1FB5FC7CF394961C1ADF5F8C6454761ADF795E67FE149F658ABE895 ) => ( 0x0000000000000000000000000000000000000000 )
AdminUpgradeabilityProxy.35817773( )
-
ContractManager.getContract( name=TokenState ) => ( contractAddress=0x4eE5F270572285776814e32952446e9B7Ee15C86 )
-
AdminUpgradeabilityProxy.fa8dacba( )
TokenState.getAndUpdateLockedAmount( holder=0x04956cAa50920968990f68e195bE59CE511a72BB ) => ( 0 )
AdminUpgradeabilityProxy.dda641ae( )
-
DelegationController.getDelegationsByHolderLength( holder=0x04956cAa50920968990f68e195bE59CE511a72BB ) => ( length=0 )
-
-
ERC1820Registry.getInterfaceImplementer( _addr=0x14f12aEeD4e904314C66BB1aA686A40B6DC6F89e, _interfaceHash=B281FC8C12954D22544DB45DE3159A39272895B169A852B314F9CC762E44C53B ) => ( 0x0000000000000000000000000000000000000000 )
File 1 of 8: SkaleToken
File 2 of 8: ERC1820Registry
File 3 of 8: AdminUpgradeabilityProxy
File 4 of 8: ContractManager
File 5 of 8: AdminUpgradeabilityProxy
File 6 of 8: TokenState
File 7 of 8: AdminUpgradeabilityProxy
File 8 of 8: DelegationController
{"BokkyPooBahsDateTimeLibrary.sol":{"content":"pragma solidity ^0.6.0;\n\n// ----------------------------------------------------------------------------\n// BokkyPooBah\u0027s DateTime Library v1.01\n//\n// A gas-efficient Solidity date and time library\n//\n// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary\n//\n// Tested date range 1970/01/01 to 2345/12/31\n//\n// Conventions:\n// Unit | Range | Notes\n// :-------- |:-------------:|:-----\n// timestamp | \u003e= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC\n// year | 1970 ... 2345 |\n// month | 1 ... 12 |\n// day | 1 ... 31 |\n// hour | 0 ... 23 |\n// minute | 0 ... 59 |\n// second | 0 ... 59 |\n// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday\n//\n//\n// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence.\n// ----------------------------------------------------------------------------\n\nlibrary BokkyPooBahsDateTimeLibrary {\n\n uint constant SECONDS_PER_DAY = 24 * 60 * 60;\n uint constant SECONDS_PER_HOUR = 60 * 60;\n uint constant SECONDS_PER_MINUTE = 60;\n int constant OFFSET19700101 = 2440588;\n\n uint constant DOW_MON = 1;\n uint constant DOW_TUE = 2;\n uint constant DOW_WED = 3;\n uint constant DOW_THU = 4;\n uint constant DOW_FRI = 5;\n uint constant DOW_SAT = 6;\n uint constant DOW_SUN = 7;\n\n // ------------------------------------------------------------------------\n // Calculate the number of days from 1970/01/01 to year/month/day using\n // the date conversion algorithm from\n // http://aa.usno.navy.mil/faq/docs/JD_Formula.php\n // and subtracting the offset 2440588 so that 1970/01/01 is day 0\n //\n // days = day\n // - 32075\n // + 1461 * (year + 4800 + (month - 14) / 12) / 4\n // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12\n // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4\n // - offset\n // ------------------------------------------------------------------------\n function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) {\n require(year \u003e= 1970);\n int _year = int(year);\n int _month = int(month);\n int _day = int(day);\n\n int __days = _day\n - 32075\n + 1461 * (_year + 4800 + (_month - 14) / 12) / 4\n + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12\n - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4\n - OFFSET19700101;\n\n _days = uint(__days);\n }\n\n // ------------------------------------------------------------------------\n // Calculate year/month/day from the number of days since 1970/01/01 using\n // the date conversion algorithm from\n // http://aa.usno.navy.mil/faq/docs/JD_Formula.php\n // and adding the offset 2440588 so that 1970/01/01 is day 0\n //\n // int L = days + 68569 + offset\n // int N = 4 * L / 146097\n // L = L - (146097 * N + 3) / 4\n // year = 4000 * (L + 1) / 1461001\n // L = L - 1461 * year / 4 + 31\n // month = 80 * L / 2447\n // dd = L - 2447 * month / 80\n // L = month / 11\n // month = month + 2 - 12 * L\n // year = 100 * (N - 49) + year + L\n // ------------------------------------------------------------------------\n function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) {\n int __days = int(_days);\n\n int L = __days + 68569 + OFFSET19700101;\n int N = 4 * L / 146097;\n L = L - (146097 * N + 3) / 4;\n int _year = 4000 * (L + 1) / 1461001;\n L = L - 1461 * _year / 4 + 31;\n int _month = 80 * L / 2447;\n int _day = L - 2447 * _month / 80;\n L = _month / 11;\n _month = _month + 2 - 12 * L;\n _year = 100 * (N - 49) + _year + L;\n\n year = uint(_year);\n month = uint(_month);\n day = uint(_day);\n }\n\n function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) {\n timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY;\n }\n function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) {\n timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second;\n }\n function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) {\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n }\n function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) {\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n uint secs = timestamp % SECONDS_PER_DAY;\n hour = secs / SECONDS_PER_HOUR;\n secs = secs % SECONDS_PER_HOUR;\n minute = secs / SECONDS_PER_MINUTE;\n second = secs % SECONDS_PER_MINUTE;\n }\n\n function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) {\n if (year \u003e= 1970 \u0026\u0026 month \u003e 0 \u0026\u0026 month \u003c= 12) {\n uint daysInMonth = _getDaysInMonth(year, month);\n if (day \u003e 0 \u0026\u0026 day \u003c= daysInMonth) {\n valid = true;\n }\n }\n }\n function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) {\n if (isValidDate(year, month, day)) {\n if (hour \u003c 24 \u0026\u0026 minute \u003c 60 \u0026\u0026 second \u003c 60) {\n valid = true;\n }\n }\n }\n function isLeapYear(uint timestamp) internal pure returns (bool leapYear) {\n uint year;\n uint month;\n uint day;\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n leapYear = _isLeapYear(year);\n }\n function _isLeapYear(uint year) internal pure returns (bool leapYear) {\n leapYear = ((year % 4 == 0) \u0026\u0026 (year % 100 != 0)) || (year % 400 == 0);\n }\n function isWeekDay(uint timestamp) internal pure returns (bool weekDay) {\n weekDay = getDayOfWeek(timestamp) \u003c= DOW_FRI;\n }\n function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) {\n weekEnd = getDayOfWeek(timestamp) \u003e= DOW_SAT;\n }\n function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) {\n uint year;\n uint month;\n uint day;\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n daysInMonth = _getDaysInMonth(year, month);\n }\n function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) {\n if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {\n daysInMonth = 31;\n } else if (month != 2) {\n daysInMonth = 30;\n } else {\n daysInMonth = _isLeapYear(year) ? 29 : 28;\n }\n }\n // 1 = Monday, 7 = Sunday\n function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) {\n uint _days = timestamp / SECONDS_PER_DAY;\n dayOfWeek = (_days + 3) % 7 + 1;\n }\n\n function getYear(uint timestamp) internal pure returns (uint year) {\n uint month;\n uint day;\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n }\n function getMonth(uint timestamp) internal pure returns (uint month) {\n uint year;\n uint day;\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n }\n function getDay(uint timestamp) internal pure returns (uint day) {\n uint year;\n uint month;\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n }\n function getHour(uint timestamp) internal pure returns (uint hour) {\n uint secs = timestamp % SECONDS_PER_DAY;\n hour = secs / SECONDS_PER_HOUR;\n }\n function getMinute(uint timestamp) internal pure returns (uint minute) {\n uint secs = timestamp % SECONDS_PER_HOUR;\n minute = secs / SECONDS_PER_MINUTE;\n }\n function getSecond(uint timestamp) internal pure returns (uint second) {\n second = timestamp % SECONDS_PER_MINUTE;\n }\n\n function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) {\n uint year;\n uint month;\n uint day;\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n year += _years;\n uint daysInMonth = _getDaysInMonth(year, month);\n if (day \u003e daysInMonth) {\n day = daysInMonth;\n }\n newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;\n require(newTimestamp \u003e= timestamp);\n }\n function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) {\n uint year;\n uint month;\n uint day;\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n month += _months;\n year += (month - 1) / 12;\n month = (month - 1) % 12 + 1;\n uint daysInMonth = _getDaysInMonth(year, month);\n if (day \u003e daysInMonth) {\n day = daysInMonth;\n }\n newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;\n require(newTimestamp \u003e= timestamp);\n }\n function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) {\n newTimestamp = timestamp + _days * SECONDS_PER_DAY;\n require(newTimestamp \u003e= timestamp);\n }\n function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) {\n newTimestamp = timestamp + _hours * SECONDS_PER_HOUR;\n require(newTimestamp \u003e= timestamp);\n }\n function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) {\n newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE;\n require(newTimestamp \u003e= timestamp);\n }\n function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) {\n newTimestamp = timestamp + _seconds;\n require(newTimestamp \u003e= timestamp);\n }\n\n function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) {\n uint year;\n uint month;\n uint day;\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n year -= _years;\n uint daysInMonth = _getDaysInMonth(year, month);\n if (day \u003e daysInMonth) {\n day = daysInMonth;\n }\n newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;\n require(newTimestamp \u003c= timestamp);\n }\n function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) {\n uint year;\n uint month;\n uint day;\n (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);\n uint yearMonth = year * 12 + (month - 1) - _months;\n year = yearMonth / 12;\n month = yearMonth % 12 + 1;\n uint daysInMonth = _getDaysInMonth(year, month);\n if (day \u003e daysInMonth) {\n day = daysInMonth;\n }\n newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;\n require(newTimestamp \u003c= timestamp);\n }\n function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) {\n newTimestamp = timestamp - _days * SECONDS_PER_DAY;\n require(newTimestamp \u003c= timestamp);\n }\n function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) {\n newTimestamp = timestamp - _hours * SECONDS_PER_HOUR;\n require(newTimestamp \u003c= timestamp);\n }\n function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) {\n newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE;\n require(newTimestamp \u003c= timestamp);\n }\n function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) {\n newTimestamp = timestamp - _seconds;\n require(newTimestamp \u003c= timestamp);\n }\n\n function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) {\n require(fromTimestamp \u003c= toTimestamp);\n uint fromYear;\n uint fromMonth;\n uint fromDay;\n uint toYear;\n uint toMonth;\n uint toDay;\n (fromYear, fromMonth, fromDay) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);\n (toYear, toMonth, toDay) = _daysToDate(toTimestamp / SECONDS_PER_DAY);\n _years = toYear - fromYear;\n }\n function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) {\n require(fromTimestamp \u003c= toTimestamp);\n uint fromYear;\n uint fromMonth;\n uint fromDay;\n uint toYear;\n uint toMonth;\n uint toDay;\n (fromYear, fromMonth, fromDay) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);\n (toYear, toMonth, toDay) = _daysToDate(toTimestamp / SECONDS_PER_DAY);\n _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;\n }\n function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) {\n require(fromTimestamp \u003c= toTimestamp);\n _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY;\n }\n function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) {\n require(fromTimestamp \u003c= toTimestamp);\n _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR;\n }\n function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) {\n require(fromTimestamp \u003c= toTimestamp);\n _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE;\n }\n function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) {\n require(fromTimestamp \u003c= toTimestamp);\n _seconds = toTimestamp - fromTimestamp;\n }\n}\n"},"ConstantsHolder.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n ConstantsHolder.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Artem Payvin\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"./Permissions.sol\";\n\n\n/**\n * @title Contains constants and common variables for Skale Manager system\n * @author Artem Payvin\n */\ncontract ConstantsHolder is Permissions {\n\n // initial price for creating Node (100 SKL)\n uint public constant NODE_DEPOSIT = 100 * 1e18;\n\n uint8 public constant TOTAL_SPACE_ON_NODE = 128;\n\n // part of Node for Small Skale-chain (1/128 of Node)\n uint8 public constant SMALL_DIVISOR = 128;\n\n // part of Node for Medium Skale-chain (1/8 of Node)\n uint8 public constant MEDIUM_DIVISOR = 8;\n\n // part of Node for Large Skale-chain (full Node)\n uint8 public constant LARGE_DIVISOR = 1;\n\n // part of Node for Medium Test Skale-chain (1/4 of Node)\n uint8 public constant MEDIUM_TEST_DIVISOR = 4;\n\n // typically number of Nodes for Skale-chain (16 Nodes)\n uint public constant NUMBER_OF_NODES_FOR_SCHAIN = 16;\n\n // number of Nodes for Test Skale-chain (2 Nodes)\n uint public constant NUMBER_OF_NODES_FOR_TEST_SCHAIN = 2;\n\n // number of Nodes for Test Skale-chain (4 Nodes)\n uint public constant NUMBER_OF_NODES_FOR_MEDIUM_TEST_SCHAIN = 4; \n\n // number of seconds in one year\n uint32 public constant SECONDS_TO_YEAR = 31622400;\n\n // initial number of monitors\n uint public constant NUMBER_OF_MONITORS = 24;\n\n uint public constant OPTIMAL_LOAD_PERCENTAGE = 80;\n\n uint public constant ADJUSTMENT_SPEED = 1000;\n\n uint public constant COOLDOWN_TIME = 60;\n\n uint public constant MIN_PRICE = 10**6;\n\n uint public constant MSR_REDUCING_COEFFICIENT = 2;\n\n uint public constant DOWNTIME_THRESHOLD_PART = 30;\n\n uint public constant BOUNTY_LOCKUP_MONTHS = 3;\n\n // MSR - Minimum staking requirement\n uint public msr;\n\n // Reward period - 30 days (each 30 days Node would be granted for bounty)\n uint32 public rewardPeriod;\n\n // Allowable latency - 150000 ms by default\n uint32 public allowableLatency;\n\n /**\n * Delta period - 1 hour (1 hour before Reward period became Monitors need\n * to send Verdicts and 1 hour after Reward period became Node need to come\n * and get Bounty)\n */\n uint32 public deltaPeriod;\n\n /**\n * Check time - 2 minutes (every 2 minutes monitors should check metrics\n * from checked nodes)\n */\n uint public checkTime;\n\n //Need to add minimal allowed parameters for verdicts\n\n uint public launchTimestamp;\n\n uint public rotationDelay;\n\n uint public proofOfUseLockUpPeriodDays;\n\n uint public proofOfUseDelegationPercentage;\n\n /**\n * Set reward and delta periods to new one, run only by owner. This function\n * only for tests.\n * @param newRewardPeriod - new Reward period\n * @param newDeltaPeriod - new Delta period\n */\n function setPeriods(uint32 newRewardPeriod, uint32 newDeltaPeriod) external onlyOwner {\n require(\n newRewardPeriod \u003e= newDeltaPeriod \u0026\u0026 newRewardPeriod - newDeltaPeriod \u003e= checkTime,\n \"Incorrect Periods\"\n );\n rewardPeriod = newRewardPeriod;\n deltaPeriod = newDeltaPeriod;\n }\n\n /**\n * Set new check time. This function only for tests.\n * @param newCheckTime - new check time\n */\n function setCheckTime(uint newCheckTime) external onlyOwner {\n require(rewardPeriod - deltaPeriod \u003e= checkTime, \"Incorrect check time\");\n checkTime = newCheckTime;\n } \n\n /**\n * Set latency new one in ms, run only by owner. This function\n * only for tests.\n * @param newAllowableLatency - new Allowable Latency\n */\n function setLatency(uint32 newAllowableLatency) external onlyOwner {\n allowableLatency = newAllowableLatency;\n }\n\n function setMSR(uint newMSR) external onlyOwner {\n msr = newMSR;\n }\n\n function setLaunchTimestamp(uint timestamp) external onlyOwner {\n require(now \u003c launchTimestamp, \"Can\u0027t set network launch timestamp because network is already launched\");\n launchTimestamp = timestamp;\n }\n\n function setRotationDelay(uint newDelay) external onlyOwner {\n rotationDelay = newDelay;\n }\n\n function setProofOfUseLockUpPeriod(uint periodDays) external onlyOwner {\n proofOfUseLockUpPeriodDays = periodDays;\n }\n\n function setProofOfUseDelegationPercentage(uint percentage) external onlyOwner {\n require(percentage \u003c= 100, \"Percentage value is incorrect\");\n proofOfUseDelegationPercentage = percentage;\n }\n\n /**\n * @dev constructor in Permissions approach\n * @param contractsAddress needed in Permissions constructor\n */\n function initialize(address contractsAddress) public override initializer {\n Permissions.initialize(contractsAddress);\n\n msr = 0;\n rewardPeriod = 86400;\n allowableLatency = 150000;\n deltaPeriod = 3600;\n checkTime = 300;\n launchTimestamp = uint(-1);\n rotationDelay = 12 hours;\n proofOfUseLockUpPeriodDays = 90;\n proofOfUseDelegationPercentage = 50;\n }\n}\n"},"ContractManager.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n ContractManager.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Artem Payvin\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"./OEPOwnable.sol\";\nimport \"./OEPAddress.sol\";\n\nimport \"./StringUtils.sol\";\n\n\n/**\n * @title Main contract in upgradeable approach. This contract contains the actual\n * current mapping from contract IDs (in the form of human-readable strings) to addresses.\n * @author Artem Payvin\n */\ncontract ContractManager is OwnableUpgradeSafe {\n using StringUtils for string;\n using Address for address;\n\n // mapping of actual smart contracts addresses\n mapping (bytes32 =\u003e address) public contracts;\n\n event ContractUpgraded(string contractsName, address contractsAddress);\n\n function initialize() external initializer {\n OwnableUpgradeSafe.__Ownable_init();\n }\n\n /**\n * Adds actual contract to mapping of actual contract addresses\n * @param contractsName - contracts name in skale manager system\n * @param newContractsAddress - contracts address in skale manager system\n */\n function setContractsAddress(string calldata contractsName, address newContractsAddress) external onlyOwner {\n // check newContractsAddress is not equal to zero\n require(newContractsAddress != address(0), \"New address is equal zero\");\n // create hash of contractsName\n bytes32 contractId = keccak256(abi.encodePacked(contractsName));\n // check newContractsAddress is not equal the previous contract\u0027s address\n require(contracts[contractId] != newContractsAddress, \"Contract is already added\");\n require(newContractsAddress.isContract(), \"Given contracts address does not contain code\");\n // add newContractsAddress to mapping of actual contract addresses\n contracts[contractId] = newContractsAddress;\n emit ContractUpgraded(contractsName, newContractsAddress);\n }\n\n function getContract(string calldata name) external view returns (address contractAddress) {\n contractAddress = contracts[keccak256(abi.encodePacked(name))];\n require(contractAddress != address(0), name.strConcat(\" contract has not been found\"));\n }\n}\n"},"DelegationController.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n DelegationController.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Dmytro Stebaiev\n @author Vadim Yavorsky\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\npragma experimental ABIEncoderV2;\n\nimport \"./OCSafeMath.sol\";\n\nimport \"./Permissions.sol\";\nimport \"./SkaleToken.sol\";\nimport \"./Nodes.sol\";\nimport \"./MathUtils.sol\";\nimport \"./FractionUtils.sol\";\n\nimport \"./DelegationPeriodManager.sol\";\nimport \"./Punisher.sol\";\nimport \"./TokenLaunchLocker.sol\";\nimport \"./TokenState.sol\";\nimport \"./ValidatorService.sol\";\nimport \"./PartialDifferences.sol\";\n\n/**\n * @title Delegation Controller\n * @dev This contract performs all delegation functions including delegation\n * requests, undelegation, slashing, etc.\n *\n * Delegators and validators may both perform delegations. Validators who perform\n * delegations to themselves are effectively self-delegating or self-bonding.\n *\n * Delegated tokens may be in one of several states:\n *\n * - PROPOSED: token holder proposes tokens to delegate to a validator\n * - ACCEPTED: token delegations are accepted by a validator and are locked-by-delegation\n * - CANCELED: token holder cancels delegation proposal. Only allowed before the proposal is accepted by the validator\n * - REJECTED: token proposal expires at the UTC start of the next month\n * - DELEGATED: accepted delegations are delegated at the UTC start of the month\n * - UNDELEGATION_REQUESTED: token holder requests delegations to undelegate from the validator\n * - COMPLETED: undelegation request is completed at the end of the delegation period\n */\ncontract DelegationController is Permissions, ILocker {\n using MathUtils for uint;\n using PartialDifferences for PartialDifferences.Sequence;\n using PartialDifferences for PartialDifferences.Value;\n using FractionUtils for FractionUtils.Fraction;\n\n enum State {\n PROPOSED,\n ACCEPTED,\n CANCELED,\n REJECTED,\n DELEGATED,\n UNDELEGATION_REQUESTED,\n COMPLETED\n }\n\n struct Delegation {\n address holder; // address of token owner\n uint validatorId;\n uint amount;\n uint delegationPeriod;\n uint created; // time of delegation creation\n uint started; // month when a delegation becomes active\n uint finished; // first month after a delegation ends\n string info;\n }\n\n struct SlashingLogEvent {\n FractionUtils.Fraction reducingCoefficient;\n uint nextMonth;\n }\n\n struct SlashingLog {\n // month =\u003e slashing event\n mapping (uint =\u003e SlashingLogEvent) slashes;\n uint firstMonth;\n uint lastMonth;\n }\n\n struct DelegationExtras {\n uint lastSlashingMonthBeforeDelegation;\n }\n\n struct SlashingEvent {\n FractionUtils.Fraction reducingCoefficient;\n uint validatorId;\n uint month;\n }\n\n struct SlashingSignal {\n address holder;\n uint penalty;\n }\n\n struct LockedInPending {\n uint amount;\n uint month;\n }\n\n struct FirstDelegationMonth {\n // month\n uint value;\n //validatorId =\u003e month\n mapping (uint =\u003e uint) byValidator;\n }\n\n /**\n * @dev Emitted when a delegation is proposed to a validator.\n */\n event DelegationProposed(\n uint delegationId\n );\n\n /**\n * @dev Emitted when a delegation is accepted by a validator.\n */\n event DelegationAccepted(\n uint delegationId\n );\n\n /**\n * @dev Emitted when a delegation is cancelled by the delegator.\n */\n event DelegationRequestCanceledByUser(\n uint delegationId\n );\n\n /**\n * @dev Emitted when a delegation is requested to undelegate.\n */\n event UndelegationRequested(\n uint delegationId\n );\n\n /// @dev delegations will never be deleted to index in this array may be used like delegation id\n Delegation[] public delegations;\n\n // validatorId =\u003e delegationId[]\n mapping (uint =\u003e uint[]) public delegationsByValidator;\n\n // holder =\u003e delegationId[]\n mapping (address =\u003e uint[]) public delegationsByHolder;\n\n // delegationId =\u003e extras\n mapping(uint =\u003e DelegationExtras) private _delegationExtras;\n\n // validatorId =\u003e sequence\n mapping (uint =\u003e PartialDifferences.Value) private _delegatedToValidator;\n // validatorId =\u003e sequence\n mapping (uint =\u003e PartialDifferences.Sequence) private _effectiveDelegatedToValidator;\n\n // validatorId =\u003e slashing log\n mapping (uint =\u003e SlashingLog) private _slashesOfValidator;\n\n // holder =\u003e sequence\n mapping (address =\u003e PartialDifferences.Value) private _delegatedByHolder;\n // holder =\u003e validatorId =\u003e sequence\n mapping (address =\u003e mapping (uint =\u003e PartialDifferences.Value)) private _delegatedByHolderToValidator;\n // holder =\u003e validatorId =\u003e sequence\n mapping (address =\u003e mapping (uint =\u003e PartialDifferences.Sequence)) private _effectiveDelegatedByHolderToValidator;\n\n SlashingEvent[] private _slashes;\n // holder =\u003e index in _slashes;\n mapping (address =\u003e uint) private _firstUnprocessedSlashByHolder;\n\n // holder =\u003e validatorId =\u003e month\n mapping (address =\u003e FirstDelegationMonth) private _firstDelegationMonth;\n\n // holder =\u003e locked in pending\n mapping (address =\u003e LockedInPending) private _lockedInPendingDelegations;\n\n /**\n * @dev Modifier to make a function callable only if delegation exists.\n */\n modifier checkDelegationExists(uint delegationId) {\n require(delegationId \u003c delegations.length, \"Delegation does not exist\");\n _;\n }\n\n function getAndUpdateDelegatedToValidatorNow(uint validatorId) external returns (uint) {\n return getAndUpdateDelegatedToValidator(validatorId, _getCurrentMonth());\n }\n\n function getAndUpdateDelegatedAmount(address holder) external returns (uint) {\n return _getAndUpdateDelegatedByHolder(holder);\n }\n\n function getAndUpdateEffectiveDelegatedByHolderToValidator(address holder, uint validatorId, uint month) external\n allow(\"Distributor\") returns (uint effectiveDelegated)\n {\n SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(holder);\n effectiveDelegated = _effectiveDelegatedByHolderToValidator[holder][validatorId]\n .getAndUpdateValueInSequence(month);\n _sendSlashingSignals(slashingSignals);\n }\n\n /**\n * @dev Allows a token holder to create a delegation proposal of an `amount`\n * and `delegationPeriod` to a `validatorId`. Delegation must be accepted\n * by the validator before the UTC start of the month, otherwise the\n * delegation will be rejected.\n *\n * The token holder may add additional information in each proposal.\n *\n * @param validatorId uint ID of validator to receive delegation proposal\n * @param amount uint amount of proposed delegation\n * @param delegationPeriod uint period of proposed delegation\n * @param info string extra information provided by the token holder (if any)\n */\n function delegate(\n uint validatorId,\n uint amount,\n uint delegationPeriod,\n string calldata info\n )\n external\n {\n\n ValidatorService validatorService = ValidatorService(contractManager.getContract(\"ValidatorService\"));\n DelegationPeriodManager delegationPeriodManager = DelegationPeriodManager(\n contractManager.getContract(\"DelegationPeriodManager\"));\n SkaleToken skaleToken = SkaleToken(contractManager.getContract(\"SkaleToken\"));\n TokenState tokenState = TokenState(contractManager.getContract(\"TokenState\"));\n\n require(\n validatorService.checkMinimumDelegation(validatorId, amount),\n \"Amount does not meet the validator\u0027s minimum delegation amount\");\n require(\n validatorService.isAuthorizedValidator(validatorId),\n \"Validator is not authorized to accept delegation request\");\n require(\n delegationPeriodManager.isDelegationPeriodAllowed(delegationPeriod),\n \"This delegation period is not allowed\");\n require(\n validatorService.isAcceptingNewRequests(validatorId),\n \"The validator is not currently accepting new requests\");\n\n SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(msg.sender);\n\n uint delegationId = _addDelegation(\n msg.sender,\n validatorId,\n amount,\n delegationPeriod,\n info);\n\n // check that there is enough money\n uint holderBalance = skaleToken.balanceOf(msg.sender);\n uint forbiddenForDelegation = tokenState.getAndUpdateForbiddenForDelegationAmount(msg.sender);\n require(holderBalance \u003e= forbiddenForDelegation, \"Token holder does not have enough tokens to delegate\");\n\n emit DelegationProposed(delegationId);\n\n _sendSlashingSignals(slashingSignals);\n }\n\n /**\n * @dev See ILocker.\n */\n function getAndUpdateLockedAmount(address wallet) external override returns (uint) {\n return _getAndUpdateLockedAmount(wallet);\n }\n\n /**\n * @dev See ILocker.\n */\n function getAndUpdateForbiddenForDelegationAmount(address wallet) external override returns (uint) {\n return _getAndUpdateLockedAmount(wallet);\n }\n\n /**\n * @dev Allows a token holder to cancel a delegation proposal.\n *\n * Requirements:\n *\n * - the sender must be the token holder of the delegation proposal.\n * - the delegation must still be in a PROPOSED state.\n *\n * Emits a DelegationRequestCanceledByUser event.\n *\n * @param delegationId uint ID of delegation proposal\n */\n function cancelPendingDelegation(uint delegationId) external checkDelegationExists(delegationId) {\n require(msg.sender == delegations[delegationId].holder, \"Only token holders can cancel delegation request\");\n require(getState(delegationId) == State.PROPOSED, \"Token holders are only able to cancel PROPOSED delegations\");\n\n delegations[delegationId].finished = _getCurrentMonth();\n _subtractFromLockedInPendingDelegations(delegations[delegationId].holder, delegations[delegationId].amount);\n\n emit DelegationRequestCanceledByUser(delegationId);\n }\n\n /**\n * @dev Allows a validator to accept a proposed delegation.\n * Successful acceptance of delegations transition the tokens from a\n * PROPOSED state to ACCEPTED, and tokens are locked for the remainder of the\n * delegation period.\n *\n * Emits a DelegationAccepted event.\n *\n * @param delegationId uint ID of delegation proposal\n */\n function acceptPendingDelegation(uint delegationId) external checkDelegationExists(delegationId) {\n ValidatorService validatorService = ValidatorService(contractManager.getContract(\"ValidatorService\"));\n require(\n validatorService.checkValidatorAddressToId(msg.sender, delegations[delegationId].validatorId),\n \"No permissions to accept request\");\n \n State currentState = getState(delegationId);\n if (currentState != State.PROPOSED) {\n if (currentState == State.ACCEPTED ||\n currentState == State.DELEGATED ||\n currentState == State.UNDELEGATION_REQUESTED ||\n currentState == State.COMPLETED)\n {\n revert(\"The delegation has been already accepted\");\n } else if (currentState == State.CANCELED) {\n revert(\"The delegation has been cancelled by token holder\");\n } else if (currentState == State.REJECTED) {\n revert(\"The delegation request is outdated\");\n }\n }\n require(currentState == State.PROPOSED, \"Cannot set delegation state to accepted\");\n \n TokenLaunchLocker tokenLaunchLocker = TokenLaunchLocker(contractManager.getContract(\"TokenLaunchLocker\"));\n\n SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(delegations[delegationId].holder);\n\n _addToAllStatistics(delegationId);\n\n tokenLaunchLocker.handleDelegationAdd(\n delegations[delegationId].holder,\n delegationId,\n delegations[delegationId].amount,\n delegations[delegationId].started);\n\n _sendSlashingSignals(slashingSignals);\n\n emit DelegationAccepted(delegationId);\n }\n\n /**\n * @dev Allows a delegator to undelegate a specific delegation.\n *\n * Requirements:\n *\n * - the sender must be the delegator.\n * - the delegation must be in DELEGATED state.\n *\n * Emits an UndelegationRequested event.\n *\n * @param delegationId uint ID of delegation to undelegate\n */\n function requestUndelegation(uint delegationId) external checkDelegationExists(delegationId) {\n require(getState(delegationId) == State.DELEGATED, \"Cannot request undelegation\");\n\n ValidatorService validatorService = ValidatorService(contractManager.getContract(\"ValidatorService\"));\n require(\n delegations[delegationId].holder == msg.sender ||\n (validatorService.validatorAddressExists(msg.sender) \u0026\u0026\n delegations[delegationId].validatorId == validatorService.getValidatorId(msg.sender)),\n \"Permission denied to request undelegation\");\n\n TokenLaunchLocker tokenLaunchLocker = TokenLaunchLocker(contractManager.getContract(\"TokenLaunchLocker\"));\n DelegationPeriodManager delegationPeriodManager = DelegationPeriodManager(\n contractManager.getContract(\"DelegationPeriodManager\"));\n\n processAllSlashes(msg.sender);\n delegations[delegationId].finished = _calculateDelegationEndMonth(delegationId);\n uint amountAfterSlashing = _calculateDelegationAmountAfterSlashing(delegationId);\n\n _removeFromDelegatedToValidator(\n delegations[delegationId].validatorId,\n amountAfterSlashing,\n delegations[delegationId].finished);\n _removeFromDelegatedByHolder(\n delegations[delegationId].holder,\n amountAfterSlashing,\n delegations[delegationId].finished);\n _removeFromDelegatedByHolderToValidator(\n delegations[delegationId].holder,\n delegations[delegationId].validatorId,\n amountAfterSlashing,\n delegations[delegationId].finished);\n uint effectiveAmount = amountAfterSlashing.mul(delegationPeriodManager.stakeMultipliers(\n delegations[delegationId].delegationPeriod));\n _removeFromEffectiveDelegatedToValidator(\n delegations[delegationId].validatorId,\n effectiveAmount,\n delegations[delegationId].finished);\n _removeFromEffectiveDelegatedByHolderToValidator(\n delegations[delegationId].holder,\n delegations[delegationId].validatorId,\n effectiveAmount,\n delegations[delegationId].finished);\n\n tokenLaunchLocker.handleDelegationRemoving(\n delegations[delegationId].holder,\n delegationId,\n delegations[delegationId].finished);\n\n emit UndelegationRequested(delegationId);\n }\n\n /**\n * @dev Allows the Punisher to confiscate an `amount` of stake from\n * `validatorId` by slashing. This slashes all delegations of the validator,\n * which reduces the amount that the validator has staked. This consequence\n * may force the SKALE Manger to reduce the number of nodes a validator is\n * operating so the validator can meet the Minimum Staking Requirement.\n *\n * See Punisher.\n *\n * Emits a SlashingEvent.\n *\n * @param validatorId uint validator to slash\n * @param amount uint amount to slash\n *\n */\n function confiscate(uint validatorId, uint amount) external allow(\"Punisher\") {\n uint currentMonth = _getCurrentMonth();\n FractionUtils.Fraction memory coefficient =\n _delegatedToValidator[validatorId].reduceValue(amount, currentMonth);\n _effectiveDelegatedToValidator[validatorId].reduceSequence(coefficient, currentMonth);\n _putToSlashingLog(_slashesOfValidator[validatorId], coefficient, currentMonth);\n _slashes.push(SlashingEvent({reducingCoefficient: coefficient, validatorId: validatorId, month: currentMonth}));\n }\n\n function getAndUpdateEffectiveDelegatedToValidator(uint validatorId, uint month)\n external allow(\"Distributor\") returns (uint)\n {\n return _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(month);\n }\n\n function getAndUpdateDelegatedByHolderToValidatorNow(address holder, uint validatorId) external returns (uint) {\n return _getAndUpdateDelegatedByHolderToValidator(holder, validatorId, _getCurrentMonth());\n }\n\n function getDelegation(uint delegationId)\n external view checkDelegationExists(delegationId) returns (Delegation memory)\n {\n return delegations[delegationId];\n }\n\n function getFirstDelegationMonth(address holder, uint validatorId) external view returns(uint) {\n return _firstDelegationMonth[holder].byValidator[validatorId];\n }\n\n function getDelegationsByValidatorLength(uint validatorId) external view returns (uint) {\n return delegationsByValidator[validatorId].length;\n }\n\n function getDelegationsByHolderLength(address holder) external view returns (uint) {\n return delegationsByHolder[holder].length;\n }\n\n function initialize(address contractsAddress) public override initializer {\n Permissions.initialize(contractsAddress);\n }\n\n function getAndUpdateDelegatedToValidator(uint validatorId, uint month)\n public allow(\"Nodes\") returns (uint)\n {\n return _delegatedToValidator[validatorId].getAndUpdateValue(month);\n }\n\n function processSlashes(address holder, uint limit) public {\n _sendSlashingSignals(_processSlashesWithoutSignals(holder, limit));\n }\n\n function processAllSlashes(address holder) public {\n processSlashes(holder, 0);\n }\n\n /**\n * @dev Returns the token state of a given delegation.\n *\n * @param delegationId uint ID of the delegation\n */\n function getState(uint delegationId) public view checkDelegationExists(delegationId) returns (State state) {\n if (delegations[delegationId].started == 0) {\n if (delegations[delegationId].finished == 0) {\n TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract(\"TimeHelpers\"));\n if (_getCurrentMonth() == timeHelpers.timestampToMonth(delegations[delegationId].created)) {\n return State.PROPOSED;\n } else {\n return State.REJECTED;\n }\n } else {\n return State.CANCELED;\n }\n } else {\n if (_getCurrentMonth() \u003c delegations[delegationId].started) {\n return State.ACCEPTED;\n } else {\n if (delegations[delegationId].finished == 0) {\n return State.DELEGATED;\n } else {\n if (_getCurrentMonth() \u003c delegations[delegationId].finished) {\n return State.UNDELEGATION_REQUESTED;\n } else {\n return State.COMPLETED;\n }\n }\n }\n }\n }\n\n function getLockedInPendingDelegations(address holder) public view returns (uint) {\n uint currentMonth = _getCurrentMonth();\n if (_lockedInPendingDelegations[holder].month \u003c currentMonth) {\n return 0;\n } else {\n return _lockedInPendingDelegations[holder].amount;\n }\n }\n\n function hasUnprocessedSlashes(address holder) public view returns (bool) {\n return _everDelegated(holder) \u0026\u0026 _firstUnprocessedSlashByHolder[holder] \u003c _slashes.length;\n }\n\n // private\n\n function _addDelegation(\n address holder,\n uint validatorId,\n uint amount,\n uint delegationPeriod,\n string memory info\n )\n private\n returns (uint delegationId)\n {\n delegationId = delegations.length;\n delegations.push(Delegation(\n holder,\n validatorId,\n amount,\n delegationPeriod,\n now,\n 0,\n 0,\n info\n ));\n delegationsByValidator[validatorId].push(delegationId);\n delegationsByHolder[holder].push(delegationId);\n _addToLockedInPendingDelegations(delegations[delegationId].holder, delegations[delegationId].amount);\n }\n\n function _calculateDelegationEndMonth(uint delegationId) private view returns (uint) {\n uint currentMonth = _getCurrentMonth();\n uint started = delegations[delegationId].started;\n\n if (currentMonth \u003c started) {\n return started.add(delegations[delegationId].delegationPeriod);\n } else {\n uint completedPeriods = currentMonth.sub(started).div(delegations[delegationId].delegationPeriod);\n return started.add(completedPeriods.add(1).mul(delegations[delegationId].delegationPeriod));\n }\n }\n\n function _addToDelegatedToValidator(uint validatorId, uint amount, uint month) private {\n _delegatedToValidator[validatorId].addToValue(amount, month);\n }\n\n function _addToEffectiveDelegatedToValidator(uint validatorId, uint effectiveAmount, uint month) private {\n _effectiveDelegatedToValidator[validatorId].addToSequence(effectiveAmount, month);\n }\n\n function _addToDelegatedByHolder(address holder, uint amount, uint month) private {\n _delegatedByHolder[holder].addToValue(amount, month);\n }\n\n function _addToDelegatedByHolderToValidator(\n address holder, uint validatorId, uint amount, uint month) private\n {\n _delegatedByHolderToValidator[holder][validatorId].addToValue(amount, month);\n }\n\n function _removeFromDelegatedByHolder(address holder, uint amount, uint month) private {\n _delegatedByHolder[holder].subtractFromValue(amount, month);\n }\n\n function _removeFromDelegatedByHolderToValidator(\n address holder, uint validatorId, uint amount, uint month) private\n {\n _delegatedByHolderToValidator[holder][validatorId].subtractFromValue(amount, month);\n }\n\n function _addToEffectiveDelegatedByHolderToValidator(\n address holder,\n uint validatorId,\n uint effectiveAmount,\n uint month)\n private\n {\n _effectiveDelegatedByHolderToValidator[holder][validatorId].addToSequence(effectiveAmount, month);\n }\n\n function _removeFromEffectiveDelegatedByHolderToValidator(\n address holder,\n uint validatorId,\n uint effectiveAmount,\n uint month)\n private\n {\n _effectiveDelegatedByHolderToValidator[holder][validatorId].subtractFromSequence(effectiveAmount, month);\n }\n\n function _getAndUpdateDelegatedByHolder(address holder) private returns (uint) {\n uint currentMonth = _getCurrentMonth();\n processAllSlashes(holder);\n return _delegatedByHolder[holder].getAndUpdateValue(currentMonth);\n }\n\n function _getAndUpdateDelegatedByHolderToValidator(\n address holder,\n uint validatorId,\n uint month)\n private returns (uint)\n {\n return _delegatedByHolderToValidator[holder][validatorId].getAndUpdateValue(month);\n }\n\n function _addToLockedInPendingDelegations(address holder, uint amount) private returns (uint) {\n uint currentMonth = _getCurrentMonth();\n if (_lockedInPendingDelegations[holder].month \u003c currentMonth) {\n _lockedInPendingDelegations[holder].amount = amount;\n _lockedInPendingDelegations[holder].month = currentMonth;\n } else {\n assert(_lockedInPendingDelegations[holder].month == currentMonth);\n _lockedInPendingDelegations[holder].amount = _lockedInPendingDelegations[holder].amount.add(amount);\n }\n }\n\n function _subtractFromLockedInPendingDelegations(address holder, uint amount) private returns (uint) {\n uint currentMonth = _getCurrentMonth();\n require(\n _lockedInPendingDelegations[holder].month == currentMonth,\n \"There are no delegation requests this month\");\n require(_lockedInPendingDelegations[holder].amount \u003e= amount, \"Unlocking amount is too big\");\n _lockedInPendingDelegations[holder].amount = _lockedInPendingDelegations[holder].amount.sub(amount);\n }\n\n function _getCurrentMonth() private view returns (uint) {\n TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract(\"TimeHelpers\"));\n return timeHelpers.getCurrentMonth();\n }\n\n function _getAndUpdateLockedAmount(address wallet) private returns (uint) {\n return _getAndUpdateDelegatedByHolder(wallet).add(getLockedInPendingDelegations(wallet));\n }\n\n function _updateFirstDelegationMonth(address holder, uint validatorId, uint month) private {\n if (_firstDelegationMonth[holder].value == 0) {\n _firstDelegationMonth[holder].value = month;\n _firstUnprocessedSlashByHolder[holder] = _slashes.length;\n }\n if (_firstDelegationMonth[holder].byValidator[validatorId] == 0) {\n _firstDelegationMonth[holder].byValidator[validatorId] = month;\n }\n }\n\n function _everDelegated(address holder) private view returns (bool) {\n return _firstDelegationMonth[holder].value \u003e 0;\n }\n\n function _removeFromDelegatedToValidator(uint validatorId, uint amount, uint month) private {\n _delegatedToValidator[validatorId].subtractFromValue(amount, month);\n }\n\n function _removeFromEffectiveDelegatedToValidator(uint validatorId, uint effectiveAmount, uint month) private {\n _effectiveDelegatedToValidator[validatorId].subtractFromSequence(effectiveAmount, month);\n }\n\n function _calculateDelegationAmountAfterSlashing(uint delegationId) private view returns (uint) {\n uint startMonth = _delegationExtras[delegationId].lastSlashingMonthBeforeDelegation;\n uint validatorId = delegations[delegationId].validatorId;\n uint amount = delegations[delegationId].amount;\n if (startMonth == 0) {\n startMonth = _slashesOfValidator[validatorId].firstMonth;\n if (startMonth == 0) {\n return amount;\n }\n }\n for (uint i = startMonth;\n i \u003e 0 \u0026\u0026 i \u003c delegations[delegationId].finished;\n i = _slashesOfValidator[validatorId].slashes[i].nextMonth) {\n if (i \u003e= delegations[delegationId].started) {\n amount = amount\n .mul(_slashesOfValidator[validatorId].slashes[i].reducingCoefficient.numerator)\n .div(_slashesOfValidator[validatorId].slashes[i].reducingCoefficient.denominator);\n }\n }\n return amount;\n }\n\n function _putToSlashingLog(\n SlashingLog storage log,\n FractionUtils.Fraction memory coefficient,\n uint month)\n private\n {\n if (log.firstMonth == 0) {\n log.firstMonth = month;\n log.lastMonth = month;\n log.slashes[month].reducingCoefficient = coefficient;\n log.slashes[month].nextMonth = 0;\n } else {\n require(log.lastMonth \u003c= month, \"Cannot put slashing event in the past\");\n if (log.lastMonth == month) {\n log.slashes[month].reducingCoefficient =\n log.slashes[month].reducingCoefficient.multiplyFraction(coefficient);\n } else {\n log.slashes[month].reducingCoefficient = coefficient;\n log.slashes[month].nextMonth = 0;\n log.slashes[log.lastMonth].nextMonth = month;\n log.lastMonth = month;\n }\n }\n }\n\n function _processSlashesWithoutSignals(address holder, uint limit)\n private returns (SlashingSignal[] memory slashingSignals)\n {\n if (hasUnprocessedSlashes(holder)) {\n uint index = _firstUnprocessedSlashByHolder[holder];\n uint end = _slashes.length;\n if (limit \u003e 0 \u0026\u0026 index.add(limit) \u003c end) {\n end = index.add(limit);\n }\n slashingSignals = new SlashingSignal[](end.sub(index));\n uint begin = index;\n for (; index \u003c end; ++index) {\n uint validatorId = _slashes[index].validatorId;\n uint month = _slashes[index].month;\n uint oldValue = _getAndUpdateDelegatedByHolderToValidator(holder, validatorId, month);\n if (oldValue.muchGreater(0)) {\n _delegatedByHolderToValidator[holder][validatorId].reduceValueByCoefficientAndUpdateSum(\n _delegatedByHolder[holder],\n _slashes[index].reducingCoefficient,\n month);\n _effectiveDelegatedByHolderToValidator[holder][validatorId].reduceSequence(\n _slashes[index].reducingCoefficient,\n month);\n slashingSignals[index.sub(begin)].holder = holder;\n slashingSignals[index.sub(begin)].penalty\n = oldValue.boundedSub(_getAndUpdateDelegatedByHolderToValidator(holder, validatorId, month));\n }\n }\n _firstUnprocessedSlashByHolder[holder] = end;\n }\n }\n\n function _processAllSlashesWithoutSignals(address holder)\n private returns (SlashingSignal[] memory slashingSignals)\n {\n return _processSlashesWithoutSignals(holder, 0);\n }\n\n function _sendSlashingSignals(SlashingSignal[] memory slashingSignals) private {\n Punisher punisher = Punisher(contractManager.getContract(\"Punisher\"));\n address previousHolder = address(0);\n uint accumulatedPenalty = 0;\n for (uint i = 0; i \u003c slashingSignals.length; ++i) {\n if (slashingSignals[i].holder != previousHolder) {\n if (accumulatedPenalty \u003e 0) {\n punisher.handleSlash(previousHolder, accumulatedPenalty);\n }\n previousHolder = slashingSignals[i].holder;\n accumulatedPenalty = slashingSignals[i].penalty;\n } else {\n accumulatedPenalty = accumulatedPenalty.add(slashingSignals[i].penalty);\n }\n }\n if (accumulatedPenalty \u003e 0) {\n punisher.handleSlash(previousHolder, accumulatedPenalty);\n }\n }\n\n function _addToAllStatistics(uint delegationId) private {\n DelegationPeriodManager delegationPeriodManager = DelegationPeriodManager(\n contractManager.getContract(\"DelegationPeriodManager\"));\n\n uint currentMonth = _getCurrentMonth();\n delegations[delegationId].started = currentMonth.add(1);\n if (_slashesOfValidator[delegations[delegationId].validatorId].lastMonth \u003e 0) {\n _delegationExtras[delegationId].lastSlashingMonthBeforeDelegation =\n _slashesOfValidator[delegations[delegationId].validatorId].lastMonth;\n }\n\n _addToDelegatedToValidator(\n delegations[delegationId].validatorId,\n delegations[delegationId].amount,\n currentMonth.add(1));\n _addToDelegatedByHolder(\n delegations[delegationId].holder,\n delegations[delegationId].amount,\n currentMonth.add(1));\n _addToDelegatedByHolderToValidator(\n delegations[delegationId].holder,\n delegations[delegationId].validatorId,\n delegations[delegationId].amount,\n currentMonth.add(1));\n _updateFirstDelegationMonth(\n delegations[delegationId].holder,\n delegations[delegationId].validatorId,\n currentMonth.add(1));\n uint effectiveAmount = delegations[delegationId].amount.mul(delegationPeriodManager.stakeMultipliers(\n delegations[delegationId].delegationPeriod));\n _addToEffectiveDelegatedToValidator(\n delegations[delegationId].validatorId,\n effectiveAmount,\n currentMonth.add(1));\n _addToEffectiveDelegatedByHolderToValidator(\n delegations[delegationId].holder,\n delegations[delegationId].validatorId,\n effectiveAmount,\n currentMonth.add(1));\n }\n}\n"},"DelegationPeriodManager.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n DelegationPeriodManager.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Dmytro Stebaiev\n @author Vadim Yavorsky\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"../Permissions.sol\";\n\n/**\n * @title Delegation Period Manager\n * @dev This contract handles all delegation offerings. Delegations are held for\n * a specified period (months), and different durations can have different\n * returns or `stakeMultiplier`. Currently, only delegation periods can be added.\n */\ncontract DelegationPeriodManager is Permissions {\n\n /**\n * @dev Emitted when a new delegation period is specified.\n */\n event DelegationPeriodWasSet(\n uint length,\n uint stakeMultiplier\n );\n\n mapping (uint =\u003e uint) public stakeMultipliers;\n\n /**\n * @dev Creates a new available delegation period and return in the network.\n * Only the owner may set new delegation period and returns in the network.\n *\n * Emits a DelegationPeriodWasSet event.\n *\n * @param monthsCount uint delegation duration in months\n * @param stakeMultiplier uint return for delegation\n */\n function setDelegationPeriod(uint monthsCount, uint stakeMultiplier) external onlyOwner {\n stakeMultipliers[monthsCount] = stakeMultiplier;\n\n emit DelegationPeriodWasSet(monthsCount, stakeMultiplier);\n }\n\n /**\n * @dev Checks whether given delegation period is allowed.\n *\n * @param monthsCount uint delegation duration in months\n * @return bool True if delegation period is allowed\n */\n function isDelegationPeriodAllowed(uint monthsCount) external view returns (bool) {\n return stakeMultipliers[monthsCount] != 0 ? true : false;\n }\n\n /**\n * @dev Initial delegation period and multiplier settings.\n */\n function initialize(address contractsAddress) public override initializer {\n Permissions.initialize(contractsAddress);\n stakeMultipliers[3] = 100; // 3 months at 100\n stakeMultipliers[6] = 150; // 6 months at 150\n stakeMultipliers[12] = 200; // 12 months at 200\n }\n}"},"ERC777.sol":{"content":"pragma solidity ^0.6.0;\n\nimport \"./OCContext.sol\";\nimport \"./OCIERC777.sol\";\nimport \"./OCIERC777Recipient.sol\";\nimport \"./OCIERC777Sender.sol\";\nimport \"./OCIERC20.sol\";\nimport \"./OCSafeMath.sol\";\n// import \"@openzeppelin/contracts/utils/Address.sol\"; Removed by SKALE\nimport \"./OCIERC1820Registry.sol\";\n\n/* Added by SKALE */\nimport \"./Permissions.sol\";\n/* End of added by SKALE */\n\n/**\n * @dev Implementation of the {IERC777} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n *\n * Support for ERC20 is included in this contract, as specified by the EIP: both\n * the ERC777 and ERC20 interfaces can be safely used when interacting with it.\n * Both {IERC777-Sent} and {IERC20-Transfer} events are emitted on token\n * movements.\n *\n * Additionally, the {IERC777-granularity} value is hard-coded to `1`, meaning that there\n * are no special restrictions in the amount of tokens that created, moved, or\n * destroyed. This makes integration with ERC20 applications seamless.\n */\ncontract ERC777 is Context, IERC777, IERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n IERC1820Registry constant internal _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n mapping(address =\u003e uint256) private _balances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n // We inline the result of the following hashes because Solidity doesn\u0027t resolve them at compile time.\n // See https://github.com/ethereum/solidity/issues/4024.\n\n // keccak256(\"ERC777TokensSender\")\n bytes32 constant private _TOKENS_SENDER_INTERFACE_HASH =\n 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;\n\n // keccak256(\"ERC777TokensRecipient\")\n bytes32 constant private _TOKENS_RECIPIENT_INTERFACE_HASH =\n 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;\n\n // This isn\u0027t ever read from - it\u0027s only used to respond to the defaultOperators query.\n address[] private _defaultOperatorsArray;\n\n // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).\n mapping(address =\u003e bool) private _defaultOperators;\n\n // For each account, a mapping of its operators and revoked default operators.\n mapping(address =\u003e mapping(address =\u003e bool)) private _operators;\n mapping(address =\u003e mapping(address =\u003e bool)) private _revokedDefaultOperators;\n\n // ERC20-allowances\n mapping (address =\u003e mapping (address =\u003e uint256)) private _allowances;\n\n /**\n * @dev `defaultOperators` may be an empty array.\n */\n constructor(\n string memory name,\n string memory symbol,\n address[] memory defaultOperators\n ) public {\n _name = name;\n _symbol = symbol;\n\n _defaultOperatorsArray = defaultOperators;\n for (uint256 i = 0; i \u003c _defaultOperatorsArray.length; i++) {\n _defaultOperators[_defaultOperatorsArray[i]] = true;\n }\n\n // register interfaces\n _ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256(\"ERC777Token\"), address(this));\n _ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256(\"ERC20Token\"), address(this));\n }\n\n /**\n * @dev See {IERC777-name}.\n */\n function name() public view override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC777-symbol}.\n */\n function symbol() public view override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {ERC20-decimals}.\n *\n * Always returns 18, as per the\n * [ERC777 EIP](https://eips.ethereum.org/EIPS/eip-777#backward-compatibility).\n */\n function decimals() public pure returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC777-granularity}.\n *\n * This implementation always returns `1`.\n */\n function granularity() public view override returns (uint256) {\n return 1;\n }\n\n /**\n * @dev See {IERC777-totalSupply}.\n */\n function totalSupply() public view override(IERC20, IERC777) returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Returns the amount of tokens owned by an account (`tokenHolder`).\n */\n function balanceOf(address tokenHolder) public view override(IERC20, IERC777) returns (uint256) {\n return _balances[tokenHolder];\n }\n\n /**\n * @dev See {IERC777-send}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function send(address recipient, uint256 amount, bytes memory data) public override {\n _send(_msgSender(), recipient, amount, data, \"\", true);\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}\n * interface if it is a contract.\n *\n * Also emits a {Sent} event.\n */\n function transfer(address recipient, uint256 amount) public override returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n\n address from = _msgSender();\n\n _callTokensToSend(from, from, recipient, amount, \"\", \"\");\n\n _move(from, from, recipient, amount, \"\", \"\");\n\n _callTokensReceived(from, from, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev See {IERC777-burn}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function burn(uint256 amount, bytes memory data) public override {\n _burn(_msgSender(), amount, data, \"\");\n }\n\n /**\n * @dev See {IERC777-isOperatorFor}.\n */\n function isOperatorFor(\n address operator,\n address tokenHolder\n ) public view override returns (bool) {\n return operator == tokenHolder ||\n (_defaultOperators[operator] \u0026\u0026 !_revokedDefaultOperators[tokenHolder][operator]) ||\n _operators[tokenHolder][operator];\n }\n\n /**\n * @dev See {IERC777-authorizeOperator}.\n */\n function authorizeOperator(address operator) public override {\n require(_msgSender() != operator, \"ERC777: authorizing self as operator\");\n\n if (_defaultOperators[operator]) {\n delete _revokedDefaultOperators[_msgSender()][operator];\n } else {\n _operators[_msgSender()][operator] = true;\n }\n\n emit AuthorizedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-revokeOperator}.\n */\n function revokeOperator(address operator) public override {\n require(operator != _msgSender(), \"ERC777: revoking self as operator\");\n\n if (_defaultOperators[operator]) {\n _revokedDefaultOperators[_msgSender()][operator] = true;\n } else {\n delete _operators[_msgSender()][operator];\n }\n\n emit RevokedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-defaultOperators}.\n */\n function defaultOperators() public view override returns (address[] memory) {\n return _defaultOperatorsArray;\n }\n\n /**\n * @dev See {IERC777-operatorSend}.\n *\n * Emits {Sent} and {IERC20-Transfer} events.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n )\n public override\n {\n require(isOperatorFor(_msgSender(), sender), \"ERC777: caller is not an operator for holder\");\n _send(sender, recipient, amount, data, operatorData, true);\n }\n\n /**\n * @dev See {IERC777-operatorBurn}.\n *\n * Emits {Burned} and {IERC20-Transfer} events.\n */\n function operatorBurn(address account, uint256 amount, bytes memory data, bytes memory operatorData) public override {\n require(isOperatorFor(_msgSender(), account), \"ERC777: caller is not an operator for holder\");\n _burn(account, amount, data, operatorData);\n }\n\n /**\n * @dev See {IERC20-allowance}.\n *\n * Note that operator and allowance concepts are orthogonal: operators may\n * not have allowance, and accounts with allowance may not be operators\n * themselves.\n */\n function allowance(address holder, address spender) public view override returns (uint256) {\n return _allowances[holder][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Note that accounts cannot have allowance issued by their operators.\n */\n function approve(address spender, uint256 value) public override returns (bool) {\n address holder = _msgSender();\n _approve(holder, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Note that operator and allowance concepts are orthogonal: operators cannot\n * call `transferFrom` (unless they have allowance), and accounts with\n * allowance cannot call `operatorSend` (unless they are operators).\n *\n * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.\n */\n function transferFrom(address holder, address recipient, uint256 amount) public override returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n require(holder != address(0), \"ERC777: transfer from the zero address\");\n\n address spender = _msgSender();\n\n _callTokensToSend(spender, holder, recipient, amount, \"\", \"\");\n\n _move(spender, holder, recipient, amount, \"\", \"\");\n _approve(holder, spender, _allowances[holder][spender].sub(amount, \"ERC777: transfer amount exceeds allowance\"));\n\n _callTokensReceived(spender, holder, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `operator`, `data` and `operatorData`.\n *\n * See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits {Minted} and {IERC20-Transfer} events.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - if `account` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function _mint(\n address account,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n )\n internal virtual\n {\n require(account != address(0), \"ERC777: mint to the zero address\");\n\n address operator = _msgSender();\n\n _beforeTokenTransfer(operator, address(0), account, amount);\n\n // Update state variables\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n\n _callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);\n\n emit Minted(operator, account, amount, userData, operatorData);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Send tokens\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _send(\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n )\n internal\n {\n require(from != address(0), \"ERC777: send from the zero address\");\n require(to != address(0), \"ERC777: send to the zero address\");\n\n address operator = _msgSender();\n\n _callTokensToSend(operator, from, to, amount, userData, operatorData);\n\n _move(operator, from, to, amount, userData, operatorData);\n\n _callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck);\n }\n\n /**\n * @dev Burn tokens\n * @param from address token holder address\n * @param amount uint256 amount of tokens to burn\n * @param data bytes extra information provided by the token holder\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _burn(\n address from,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n )\n internal virtual\n {\n require(from != address(0), \"ERC777: burn from the zero address\");\n\n address operator = _msgSender();\n\n /* Chaged by SKALE: we swapped these lines to prevent delegation of burning tokens */\n\n _callTokensToSend(operator, from, address(0), amount, data, operatorData);\n\n _beforeTokenTransfer(operator, from, address(0), amount);\n\n /* End of changed by SKALE */\n\n // Update state variables\n _balances[from] = _balances[from].sub(amount, \"ERC777: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n\n emit Burned(operator, from, amount, data, operatorData);\n emit Transfer(from, address(0), amount);\n }\n\n function _move(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n )\n private\n {\n _beforeTokenTransfer(operator, from, to, amount);\n\n _balances[from] = _balances[from].sub(amount, \"ERC777: transfer amount exceeds balance\");\n _balances[to] = _balances[to].add(amount);\n\n emit Sent(operator, from, to, amount, userData, operatorData);\n emit Transfer(from, to, amount);\n }\n\n /**\n * @dev See {ERC20-_approve}.\n *\n * Note that accounts cannot have allowance issued by their operators.\n */\n function _approve(address holder, address spender, uint256 value) internal {\n require(holder != address(0), \"ERC777: approve from the zero address\");\n require(spender != address(0), \"ERC777: approve to the zero address\");\n\n _allowances[holder][spender] = value;\n emit Approval(holder, spender, value);\n }\n\n /**\n * @dev Call from.tokensToSend() if the interface is registered\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _callTokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n )\n /* Chaged by SKALE from private */ internal /* End of changed by SKALE */\n /* Added by SKALE */ virtual /* End of added by SKALE */\n {\n address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(from, _TOKENS_SENDER_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData);\n }\n }\n\n /**\n * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but\n * tokensReceived() was not registered for the recipient\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _callTokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n )\n /* Chaged by SKALE from private */ internal /* End of changed by SKALE */\n /* Added by SKALE */ virtual /* End of added by SKALE */\n {\n address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(to, _TOKENS_RECIPIENT_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData);\n } else if (requireReceptionAck) {\n require(!to.isContract(), \"ERC777: token recipient contract has no implementer for ERC777TokensRecipient\");\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes\n * calls to {send}, {transfer}, {operatorSend}, minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, ``from``\u0027s `tokenId` will be\n * transferred to `to`.\n * - when `from` is zero, `tokenId` will be minted for `to`.\n * - when `to` is zero, ``from``\u0027s `tokenId` will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(address operator, address from, address to, uint256 tokenId) internal virtual { }\n}\n"},"FractionUtils.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n FractionUtils.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Dmytro Stebaiev\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"./OCSafeMath.sol\";\n\n\nlibrary FractionUtils {\n using SafeMath for uint;\n\n struct Fraction {\n uint numerator;\n uint denominator;\n }\n\n function createFraction(uint numerator, uint denominator) internal pure returns (Fraction memory) {\n require(denominator \u003e 0, \"Division by zero\");\n Fraction memory fraction = Fraction({numerator: numerator, denominator: denominator});\n reduceFraction(fraction);\n return fraction;\n }\n\n function createFraction(uint value) internal pure returns (Fraction memory) {\n return createFraction(value, 1);\n }\n\n function reduceFraction(Fraction memory fraction) internal pure {\n uint _gcd = gcd(fraction.numerator, fraction.denominator);\n fraction.numerator = fraction.numerator.div(_gcd);\n fraction.denominator = fraction.denominator.div(_gcd);\n }\n\n function multiplyFraction(Fraction memory a, Fraction memory b) internal pure returns (Fraction memory) {\n return createFraction(a.numerator.mul(b.numerator), a.denominator.mul(b.denominator));\n }\n\n function gcd(uint a, uint b) internal pure returns (uint) {\n uint _a = a;\n uint _b = b;\n if (_b \u003e _a) {\n (_a, _b) = swap(_a, _b);\n }\n while (_b \u003e 0) {\n _a = _a.mod(_b);\n (_a, _b) = swap (_a, _b);\n }\n return _a;\n }\n\n function swap(uint a, uint b) internal pure returns (uint, uint) {\n return (b, a);\n }\n}"},"IDelegatableToken.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n IDelegatableToken.sol - SKALE Manager\n Copyright (C) 2019-Present SKALE Labs\n @author Dmytro Stebaiev\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\n/**\n * @dev Interface of Delegatable Token operations.\n */\ninterface IDelegatableToken {\n /**\n * @dev Updates and returns the amount of locked tokens of a given account (`wallet`).\n */\n function getAndUpdateLockedAmount(address wallet) external returns (uint);\n /**\n * @dev Updates and returns the amount of delegated tokens of a given account (`wallet`).\n */\n function getAndUpdateDelegatedAmount(address wallet) external returns (uint);\n /**\n * @dev Updates and returns the amount of slashed tokens of a given account (`wallet`).\n */\n function getAndUpdateSlashedAmount(address wallet) external returns (uint);\n}"},"ILocker.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n ILocker.sol - SKALE Manager\n Copyright (C) 2019-Present SKALE Labs\n @author Dmytro Stebaiev\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\n/**\n * @dev Interface of Locker functions of the {TokenState} contract.\n *\n * The SKALE Network has three types of locked tokens:\n *\n * - Tokens that are transferrable but are currently locked into delegation with\n * a validator. See {DelegationController};\n *\n * - Tokens that are not transferable from one address to another, but may be\n * delegated to a validator {getAndUpdateLockedAmount}. This lock enforces\n * Proof-of-Use requirements. See {TokenLaunchLocker}; and,\n *\n * - Tokens that are neither transferable nor delegatable\n * {getAndUpdateForbiddenForDelegationAmount}. This lock enforces slashing.\n * See {Punisher}.\n */\ninterface ILocker {\n /**\n * @dev Returns the locked amount of untransferable tokens of a given `wallet`\n */\n function getAndUpdateLockedAmount(address wallet) external returns (uint);\n\n /**\n * @dev Returns the locked amount of untransferable and un-delegatable tokens of a given `wallet`.\n */\n function getAndUpdateForbiddenForDelegationAmount(address wallet) external returns (uint);\n}\n"},"MathUtils.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n StringUtils.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Dmytro Stebaiev\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\n\nlibrary MathUtils {\n event UnderflowError(\n uint a,\n uint b\n );\n\n uint constant private _EPS = 1e6;\n\n function boundedSub(uint256 a, uint256 b) internal returns (uint256) {\n if (a \u003e= b) {\n return a - b;\n } else {\n emit UnderflowError(a, b);\n return 0;\n }\n }\n\n function boundedSubWithoutEvent(uint256 a, uint256 b) internal pure returns (uint256) {\n if (a \u003e= b) {\n return a - b;\n } else {\n return 0;\n }\n }\n\n function muchGreater(uint256 a, uint256 b) internal pure returns (bool) {\n assert(uint(-1) - _EPS \u003e b);\n return a \u003e b + _EPS;\n }\n\n function approximatelyEqual(uint256 a, uint256 b) internal pure returns (bool) {\n if (a \u003e b) {\n return a - b \u003c _EPS;\n } else {\n return b - a \u003c _EPS;\n }\n }\n}"},"Nodes.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n Nodes.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Artem Payvin\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\npragma experimental ABIEncoderV2;\n\nimport \"./OCSafeCast.sol\";\n\nimport \"./Permissions.sol\";\nimport \"./ConstantsHolder.sol\";\nimport \"./ValidatorService.sol\";\nimport \"./DelegationController.sol\";\n\n\n/**\n * @title Nodes - contract contains all functionality logic to manage Nodes\n */\ncontract Nodes is Permissions {\n \n using SafeCast for uint;\n\n // All Nodes states\n enum NodeStatus {Active, Leaving, Left}\n\n struct Node {\n string name;\n bytes4 ip;\n bytes4 publicIP;\n uint16 port;\n bytes32[2] publicKey;\n uint startBlock;\n uint lastRewardDate;\n uint finishTime;\n NodeStatus status;\n uint validatorId;\n }\n\n // struct to note which Nodes and which number of Nodes owned by user\n struct CreatedNodes {\n mapping (uint =\u003e bool) isNodeExist;\n uint numberOfNodes;\n }\n\n struct SpaceManaging {\n uint8 freeSpace;\n uint indexInSpaceMap;\n }\n\n // TODO: move outside the contract\n struct NodeCreationParams {\n string name;\n bytes4 ip;\n bytes4 publicIp;\n uint16 port;\n bytes32[2] publicKey;\n uint16 nonce;\n }\n\n // array which contain all Nodes\n Node[] public nodes;\n\n SpaceManaging[] public spaceOfNodes;\n\n // mapping for checking which Nodes and which number of Nodes owned by user\n mapping (address =\u003e CreatedNodes) public nodeIndexes;\n // mapping for checking is IP address busy\n mapping (bytes4 =\u003e bool) public nodesIPCheck;\n // mapping for checking is Name busy\n mapping (bytes32 =\u003e bool) public nodesNameCheck;\n // mapping for indication from Name to Index\n mapping (bytes32 =\u003e uint) public nodesNameToIndex;\n // mapping for indication from space to Nodes\n mapping (uint8 =\u003e uint[]) public spaceToNodes;\n\n mapping (uint =\u003e uint[]) public validatorToNodeIndexes;\n\n uint public numberOfActiveNodes;\n uint public numberOfLeavingNodes;\n uint public numberOfLeftNodes;\n\n // informs that Node is created\n event NodeCreated(\n uint nodeIndex,\n address owner,\n string name,\n bytes4 ip,\n bytes4 publicIP,\n uint16 port,\n uint16 nonce,\n uint time,\n uint gasSpend\n );\n\n // informs that node is fully finished quitting from the system\n event ExitCompleted(\n uint nodeIndex,\n uint time,\n uint gasSpend\n );\n\n // informs that owner starts the procedure of quitting the Node from the system\n event ExitInited(\n uint nodeIndex,\n uint startLeavingPeriod,\n uint time,\n uint gasSpend\n );\n\n /**\n * @dev removeSpaceFromFractionalNode - occupies space from Fractional Node\n * function could be run only by Schains\n * @param nodeIndex - index of Node at array of Fractional Nodes\n * @param space - space which should be occupied\n */\n function removeSpaceFromNode(uint nodeIndex, uint8 space)\n external\n allowTwo(\"NodeRotation\", \"SchainsInternal\")\n returns (bool)\n {\n if (spaceOfNodes[nodeIndex].freeSpace \u003c space) {\n return false;\n }\n if (space \u003e 0) {\n _moveNodeToNewSpaceMap(\n nodeIndex,\n uint(spaceOfNodes[nodeIndex].freeSpace).sub(space).toUint8()\n );\n }\n return true;\n }\n\n /**\n * @dev adSpaceToFractionalNode - returns space to Fractional Node\n * function could be run only be Schains\n * @param nodeIndex - index of Node at array of Fractional Nodes\n * @param space - space which should be returned\n */\n function addSpaceToNode(uint nodeIndex, uint8 space) external allow(\"Schains\") {\n if (space \u003e 0) {\n _moveNodeToNewSpaceMap(\n nodeIndex,\n uint(spaceOfNodes[nodeIndex].freeSpace).add(space).toUint8()\n );\n }\n }\n\n /**\n * @dev changeNodeLastRewardDate - changes Node\u0027s last reward date\n * function could be run only by SkaleManager\n * @param nodeIndex - index of Node\n */\n function changeNodeLastRewardDate(uint nodeIndex) external allow(\"SkaleManager\") {\n nodes[nodeIndex].lastRewardDate = block.timestamp;\n }\n\n function changeNodeFinishTime(uint nodeIndex, uint time) external allow(\"SkaleManager\") {\n nodes[nodeIndex].finishTime = time;\n }\n\n /**\n * @dev createNode - creates new Node and add it to the Nodes contract\n * function could be only run by SkaleManager\n * @param from - owner of Node\n * @return nodeIndex - index of Node\n */\n function createNode(address from, NodeCreationParams calldata params)\n external\n allow(\"SkaleManager\")\n returns (uint nodeIndex)\n {\n // checks that Node has correct data\n require(params.ip != 0x0 \u0026\u0026 !nodesIPCheck[params.ip], \"IP address is zero or is not available\");\n require(!nodesNameCheck[keccak256(abi.encodePacked(params.name))], \"Name has already registered\");\n require(params.port \u003e 0, \"Port is zero\");\n\n uint validatorId = ValidatorService(\n contractManager.getContract(\"ValidatorService\")).getValidatorIdByNodeAddress(from);\n\n // adds Node to Nodes contract\n nodeIndex = _addNode(\n from,\n params.name,\n params.ip,\n params.publicIp,\n params.port,\n params.publicKey,\n validatorId);\n\n emit NodeCreated(\n nodeIndex,\n from,\n params.name,\n params.ip,\n params.publicIp,\n params.port,\n params.nonce,\n block.timestamp,\n gasleft());\n }\n\n /**\n * @dev initExit - initiate a procedure of quitting the system\n * function could be only run by SkaleManager\n * @param nodeIndex - index of Node\n * @return true - if everything OK\n */\n function initExit(uint nodeIndex) external allow(\"SkaleManager\") returns (bool) {\n\n _setNodeLeaving(nodeIndex);\n\n emit ExitInited(\n nodeIndex,\n block.timestamp,\n block.timestamp,\n gasleft());\n return true;\n }\n\n /**\n * @dev completeExit - finish a procedure of quitting the system\n * function could be run only by SkaleManager\n * @param nodeIndex - index of Node\n * @return amount of SKL which be returned\n */\n function completeExit(uint nodeIndex) external allow(\"SkaleManager\") returns (bool) {\n require(isNodeLeaving(nodeIndex), \"Node is not Leaving\");\n\n _setNodeLeft(nodeIndex);\n _deleteNode(nodeIndex);\n\n emit ExitCompleted(\n nodeIndex,\n block.timestamp,\n gasleft());\n return true;\n }\n\n function deleteNodeForValidator(uint validatorId, uint nodeIndex) external allow(\"SkaleManager\") {\n ValidatorService validatorService = ValidatorService(contractManager.getContract(\"ValidatorService\"));\n require(validatorService.validatorExists(validatorId), \"Validator with such ID does not exist\");\n uint[] memory validatorNodes = validatorToNodeIndexes[validatorId];\n uint position = _findNode(validatorNodes, nodeIndex);\n if (position \u003c validatorNodes.length) {\n validatorToNodeIndexes[validatorId][position] =\n validatorToNodeIndexes[validatorId][validatorNodes.length.sub(1)];\n }\n validatorToNodeIndexes[validatorId].pop();\n }\n\n function checkPossibilityCreatingNode(address nodeAddress) external allow(\"SkaleManager\") {\n ValidatorService validatorService = ValidatorService(contractManager.getContract(\"ValidatorService\"));\n DelegationController delegationController = DelegationController(\n contractManager.getContract(\"DelegationController\")\n );\n uint validatorId = validatorService.getValidatorIdByNodeAddress(nodeAddress);\n require(validatorService.isAuthorizedValidator(validatorId), \"Validator is not authorized to create a node\");\n uint[] memory validatorNodes = validatorToNodeIndexes[validatorId];\n uint delegationsTotal = delegationController.getAndUpdateDelegatedToValidatorNow(validatorId);\n uint msr = ConstantsHolder(contractManager.getContract(\"ConstantsHolder\")).msr();\n require(\n validatorNodes.length.add(1).mul(msr) \u003c= delegationsTotal,\n \"Validator must meet the Minimum Staking Requirement\");\n }\n\n function checkPossibilityToMaintainNode(\n uint validatorId,\n uint nodeIndex\n )\n external\n allow(\"Bounty\")\n returns (bool)\n {\n DelegationController delegationController = DelegationController(\n contractManager.getContract(\"DelegationController\")\n );\n ValidatorService validatorService = ValidatorService(contractManager.getContract(\"ValidatorService\"));\n require(validatorService.validatorExists(validatorId), \"Validator with such ID does not exist\");\n uint[] memory validatorNodes = validatorToNodeIndexes[validatorId];\n uint position = _findNode(validatorNodes, nodeIndex);\n require(position \u003c validatorNodes.length, \"Node does not exist for this Validator\");\n uint delegationsTotal = delegationController.getAndUpdateDelegatedToValidatorNow(validatorId);\n uint msr = ConstantsHolder(contractManager.getContract(\"ConstantsHolder\")).msr();\n return position.add(1).mul(msr) \u003c= delegationsTotal;\n }\n\n function getNodesWithFreeSpace(uint8 freeSpace) external view returns (uint[] memory) {\n ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract(\"ConstantsHolder\"));\n uint[] memory nodesWithFreeSpace = new uint[](countNodesWithFreeSpace(freeSpace));\n uint cursor = 0;\n for (uint8 i = freeSpace; i \u003c= constantsHolder.TOTAL_SPACE_ON_NODE(); ++i) {\n for (uint j = 0; j \u003c spaceToNodes[i].length; j++) {\n nodesWithFreeSpace[cursor] = spaceToNodes[i][j];\n ++cursor;\n }\n }\n return nodesWithFreeSpace;\n }\n\n /**\n * @dev isTimeForReward - checks if time for reward has come\n * @param nodeIndex - index of Node\n * @return if time for reward has come - true, else - false\n */\n function isTimeForReward(uint nodeIndex) external view returns (bool) {\n ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract(\"ConstantsHolder\"));\n return uint(nodes[nodeIndex].lastRewardDate).add(constantsHolder.rewardPeriod()) \u003c= block.timestamp;\n }\n\n /**\n * @dev isNodeExist - checks existence of Node at this address\n * @param from - account address\n * @param nodeIndex - index of Node\n * @return if exist - true, else - false\n */\n function isNodeExist(address from, uint nodeIndex) external view returns (bool) {\n return nodeIndexes[from].isNodeExist[nodeIndex];\n }\n\n /**\n * @dev getNodeIP - get ip address of Node\n * @param nodeIndex - index of Node\n * @return ip address\n */\n function getNodeIP(uint nodeIndex) external view returns (bytes4) {\n require(nodeIndex \u003c nodes.length, \"Node does not exist\");\n return nodes[nodeIndex].ip;\n }\n\n /**\n * @dev getNodePort - get Node\u0027s port\n * @param nodeIndex - index of Node\n * @return port\n */\n function getNodePort(uint nodeIndex) external view returns (uint16) {\n return nodes[nodeIndex].port;\n }\n\n function getNodePublicKey(uint nodeIndex) external view returns (bytes32[2] memory) {\n return nodes[nodeIndex].publicKey;\n }\n\n function getNodeFinishTime(uint nodeIndex) external view returns (uint) {\n return nodes[nodeIndex].finishTime;\n }\n\n /**\n * @dev isNodeLeft - checks if Node status Left\n * @param nodeIndex - index of Node\n * @return if Node status Left - true, else - false\n */\n function isNodeLeft(uint nodeIndex) external view returns (bool) {\n return nodes[nodeIndex].status == NodeStatus.Left;\n }\n\n /**\n * @dev getNodeLastRewardDate - get Node last reward date\n * @param nodeIndex - index of Node\n * @return Node last reward date\n */\n function getNodeLastRewardDate(uint nodeIndex) external view returns (uint) {\n return nodes[nodeIndex].lastRewardDate;\n }\n\n /**\n * @dev getNodeNextRewardDate - get Node next reward date\n * @param nodeIndex - index of Node\n * @return Node next reward date\n */\n function getNodeNextRewardDate(uint nodeIndex) external view returns (uint) {\n ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract(\"ConstantsHolder\"));\n return nodes[nodeIndex].lastRewardDate.add(constantsHolder.rewardPeriod());\n }\n\n /**\n * @dev getNumberOfNodes - get number of Nodes\n * @return number of Nodes\n */\n function getNumberOfNodes() external view returns (uint) {\n return nodes.length;\n }\n\n /**\n * @dev getNumberOfFullNodes - get number Online Nodes\n * @return number of active nodes plus number of leaving nodes\n */\n function getNumberOnlineNodes() external view returns (uint) {\n return numberOfActiveNodes.add(numberOfLeavingNodes);\n }\n\n /**\n * @dev getActiveNodeIPs - get array of ips of Active Nodes\n * @return activeNodeIPs - array of ips of Active Nodes\n */\n function getActiveNodeIPs() external view returns (bytes4[] memory activeNodeIPs) {\n activeNodeIPs = new bytes4[](numberOfActiveNodes);\n uint indexOfActiveNodeIPs = 0;\n for (uint indexOfNodes = 0; indexOfNodes \u003c nodes.length; indexOfNodes++) {\n if (isNodeActive(indexOfNodes)) {\n activeNodeIPs[indexOfActiveNodeIPs] = nodes[indexOfNodes].ip;\n indexOfActiveNodeIPs++;\n }\n }\n }\n\n /**\n * @dev getActiveNodesByAddress - get array of indexes of Active Nodes, which were\n * created by msg.sender\n * @return activeNodesByAddress Array of indexes of Active Nodes, which were created by msg.sender\n */\n function getActiveNodesByAddress() external view returns (uint[] memory activeNodesByAddress) {\n activeNodesByAddress = new uint[](nodeIndexes[msg.sender].numberOfNodes);\n uint indexOfActiveNodesByAddress = 0;\n for (uint indexOfNodes = 0; indexOfNodes \u003c nodes.length; indexOfNodes++) {\n if (nodeIndexes[msg.sender].isNodeExist[indexOfNodes] \u0026\u0026 isNodeActive(indexOfNodes)) {\n activeNodesByAddress[indexOfActiveNodesByAddress] = indexOfNodes;\n indexOfActiveNodesByAddress++;\n }\n }\n }\n\n /**\n * @dev getActiveNodeIds - get array of indexes of Active Nodes\n * @return activeNodeIds - array of indexes of Active Nodes\n */\n function getActiveNodeIds() external view returns (uint[] memory activeNodeIds) {\n activeNodeIds = new uint[](numberOfActiveNodes);\n uint indexOfActiveNodeIds = 0;\n for (uint indexOfNodes = 0; indexOfNodes \u003c nodes.length; indexOfNodes++) {\n if (isNodeActive(indexOfNodes)) {\n activeNodeIds[indexOfActiveNodeIds] = indexOfNodes;\n indexOfActiveNodeIds++;\n }\n }\n }\n\n function getValidatorId(uint nodeIndex) external view returns (uint) {\n require(nodeIndex \u003c nodes.length, \"Node does not exist\");\n return nodes[nodeIndex].validatorId;\n }\n\n function getNodeStatus(uint nodeIndex) external view returns (NodeStatus) {\n return nodes[nodeIndex].status;\n }\n\n function getValidatorNodeIndexes(uint validatorId) external view returns (uint[] memory) {\n ValidatorService validatorService = ValidatorService(contractManager.getContract(\"ValidatorService\"));\n require(validatorService.validatorExists(validatorId), \"Validator with such ID does not exist\");\n return validatorToNodeIndexes[validatorId];\n }\n\n /**\n * @dev constructor in Permissions approach\n * @param contractsAddress needed in Permissions constructor\n */\n function initialize(address contractsAddress) public override initializer {\n Permissions.initialize(contractsAddress);\n\n numberOfActiveNodes = 0;\n numberOfLeavingNodes = 0;\n numberOfLeftNodes = 0;\n }\n\n /**\n * @dev isNodeActive - checks if Node status Active\n * @param nodeIndex - index of Node\n * @return if Node status Active - true, else - false\n */\n function isNodeActive(uint nodeIndex) public view returns (bool) {\n return nodes[nodeIndex].status == NodeStatus.Active;\n }\n\n /**\n * @dev isNodeLeaving - checks if Node status Leaving\n * @param nodeIndex - index of Node\n * @return if Node status Leaving - true, else - false\n */\n function isNodeLeaving(uint nodeIndex) public view returns (bool) {\n return nodes[nodeIndex].status == NodeStatus.Leaving;\n }\n\n function countNodesWithFreeSpace(uint8 freeSpace) public view returns (uint count) {\n ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract(\"ConstantsHolder\"));\n count = 0;\n for (uint8 i = freeSpace; i \u003c= constantsHolder.TOTAL_SPACE_ON_NODE(); ++i) {\n count = count.add(spaceToNodes[i].length);\n }\n }\n\n function _findNode(uint[] memory validatorNodeIndexes, uint nodeIndex) private pure returns (uint) {\n uint i;\n for (i = 0; i \u003c validatorNodeIndexes.length; i++) {\n if (validatorNodeIndexes[i] == nodeIndex) {\n return i;\n }\n }\n return validatorNodeIndexes.length;\n }\n\n function _moveNodeToNewSpaceMap(uint nodeIndex, uint8 newSpace) private {\n uint8 previousSpace = spaceOfNodes[nodeIndex].freeSpace;\n uint indexInArray = spaceOfNodes[nodeIndex].indexInSpaceMap;\n if (indexInArray \u003c spaceToNodes[previousSpace].length.sub(1)) {\n uint shiftedIndex = spaceToNodes[previousSpace][spaceToNodes[previousSpace].length.sub(1)];\n spaceToNodes[previousSpace][indexInArray] = shiftedIndex;\n spaceOfNodes[shiftedIndex].indexInSpaceMap = indexInArray;\n spaceToNodes[previousSpace].pop();\n } else {\n spaceToNodes[previousSpace].pop();\n }\n spaceToNodes[newSpace].push(nodeIndex);\n spaceOfNodes[nodeIndex].freeSpace = newSpace;\n spaceOfNodes[nodeIndex].indexInSpaceMap = spaceToNodes[newSpace].length.sub(1);\n }\n\n /**\n * @dev _setNodeLeft - set Node Left\n * function could be run only by Nodes\n * @param nodeIndex - index of Node\n */\n function _setNodeLeft(uint nodeIndex) private {\n nodesIPCheck[nodes[nodeIndex].ip] = false;\n nodesNameCheck[keccak256(abi.encodePacked(nodes[nodeIndex].name))] = false;\n delete nodesNameToIndex[keccak256(abi.encodePacked(nodes[nodeIndex].name))];\n if (nodes[nodeIndex].status == NodeStatus.Active) {\n numberOfActiveNodes--;\n } else {\n numberOfLeavingNodes--;\n }\n nodes[nodeIndex].status = NodeStatus.Left;\n numberOfLeftNodes++;\n }\n\n /**\n * @dev _setNodeLeaving - set Node Leaving\n * function could be run only by Nodes\n * @param nodeIndex - index of Node\n */\n function _setNodeLeaving(uint nodeIndex) private {\n nodes[nodeIndex].status = NodeStatus.Leaving;\n numberOfActiveNodes--;\n numberOfLeavingNodes++;\n }\n\n /**\n * @dev _addNode - adds Node to array\n * function could be run only by executor\n * @param from - owner of Node\n * @param name - Node name\n * @param ip - Node ip\n * @param publicIP - Node public ip\n * @param port - Node public port\n * @param publicKey - Ethereum public key\n * @return nodeIndex Index of Node\n */\n function _addNode(\n address from,\n string memory name,\n bytes4 ip,\n bytes4 publicIP,\n uint16 port,\n bytes32[2] memory publicKey,\n uint validatorId\n )\n private\n returns (uint nodeIndex)\n {\n ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract(\"ConstantsHolder\"));\n nodes.push(Node({\n name: name,\n ip: ip,\n publicIP: publicIP,\n port: port,\n //owner: from,\n publicKey: publicKey,\n startBlock: block.number,\n lastRewardDate: block.timestamp,\n finishTime: 0,\n status: NodeStatus.Active,\n validatorId: validatorId\n }));\n nodeIndex = nodes.length.sub(1);\n validatorToNodeIndexes[validatorId].push(nodeIndex);\n bytes32 nodeId = keccak256(abi.encodePacked(name));\n nodesIPCheck[ip] = true;\n nodesNameCheck[nodeId] = true;\n nodesNameToIndex[nodeId] = nodeIndex;\n nodeIndexes[from].isNodeExist[nodeIndex] = true;\n nodeIndexes[from].numberOfNodes++;\n spaceOfNodes.push(SpaceManaging({\n freeSpace: constantsHolder.TOTAL_SPACE_ON_NODE(),\n indexInSpaceMap: spaceToNodes[constantsHolder.TOTAL_SPACE_ON_NODE()].length\n }));\n spaceToNodes[constantsHolder.TOTAL_SPACE_ON_NODE()].push(nodeIndex);\n numberOfActiveNodes++;\n }\n\n function _deleteNode(uint nodeIndex) private {\n uint8 space = spaceOfNodes[nodeIndex].freeSpace;\n uint indexInArray = spaceOfNodes[nodeIndex].indexInSpaceMap;\n if (indexInArray \u003c spaceToNodes[space].length.sub(1)) {\n uint shiftedIndex = spaceToNodes[space][spaceToNodes[space].length.sub(1)];\n spaceToNodes[space][indexInArray] = shiftedIndex;\n spaceOfNodes[shiftedIndex].indexInSpaceMap = indexInArray;\n spaceToNodes[space].pop();\n } else {\n spaceToNodes[space].pop();\n }\n delete spaceOfNodes[nodeIndex].freeSpace;\n delete spaceOfNodes[nodeIndex].indexInSpaceMap;\n }\n\n}\n"},"OCContext.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n"},"OCECDSA.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n // Check the signature length\n if (signature.length != 65) {\n revert(\"ECDSA: invalid signature length\");\n }\n\n // Divide the signature in r, s and v variables\n bytes32 r;\n bytes32 s;\n uint8 v;\n\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n // solhint-disable-next-line no-inline-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (281): 0 \u003c s \u003c secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) \u003e 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n revert(\"ECDSA: invalid signature \u0027s\u0027 value\");\n }\n\n if (v != 27 \u0026\u0026 v != 28) {\n revert(\"ECDSA: invalid signature \u0027v\u0027 value\");\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n require(signer != address(0), \"ECDSA: invalid signature\");\n\n return signer;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * replicates the behavior of the\n * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]\n * JSON-RPC method.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n}\n"},"OCIERC1820Registry.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Interface of the global ERC1820 Registry, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register\n * implementers for interfaces in this registry, as well as query support.\n *\n * Implementers may be shared by multiple accounts, and can also implement more\n * than a single interface for each account. Contracts can implement interfaces\n * for themselves, but externally-owned accounts (EOA) must delegate this to a\n * contract.\n *\n * {IERC165} interfaces can also be queried via the registry.\n *\n * For an in-depth explanation and source code analysis, see the EIP text.\n */\ninterface IERC1820Registry {\n /**\n * @dev Sets `newManager` as the manager for `account`. A manager of an\n * account is able to set interface implementers for it.\n *\n * By default, each account is its own manager. Passing a value of `0x0` in\n * `newManager` will reset the manager to this initial state.\n *\n * Emits a {ManagerChanged} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n */\n function setManager(address account, address newManager) external;\n\n /**\n * @dev Returns the manager for `account`.\n *\n * See {setManager}.\n */\n function getManager(address account) external view returns (address);\n\n /**\n * @dev Sets the `implementer` contract as ``account``\u0027s implementer for\n * `interfaceHash`.\n *\n * `account` being the zero address is an alias for the caller\u0027s address.\n * The zero address can also be used in `implementer` to remove an old one.\n *\n * See {interfaceHash} to learn how these are created.\n *\n * Emits an {InterfaceImplementerSet} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not\n * end in 28 zeroes).\n * - `implementer` must implement {IERC1820Implementer} and return true when\n * queried for support, unless `implementer` is the caller. See\n * {IERC1820Implementer-canImplementInterfaceForAddress}.\n */\n function setInterfaceImplementer(address account, bytes32 interfaceHash, address implementer) external;\n\n /**\n * @dev Returns the implementer of `interfaceHash` for `account`. If no such\n * implementer is registered, returns the zero address.\n *\n * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28\n * zeroes), `account` will be queried for support of it.\n *\n * `account` being the zero address is an alias for the caller\u0027s address.\n */\n function getInterfaceImplementer(address account, bytes32 interfaceHash) external view returns (address);\n\n /**\n * @dev Returns the interface hash for an `interfaceName`, as defined in the\n * corresponding\n * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].\n */\n function interfaceHash(string calldata interfaceName) external pure returns (bytes32);\n\n /**\n * @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n * @param account Address of the contract for which to update the cache.\n * @param interfaceId ERC165 interface for which to update the cache.\n */\n function updateERC165Cache(address account, bytes4 interfaceId) external;\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not.\n * If the result is not cached a direct lookup on the contract address is performed.\n * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n * {updateERC165Cache} with the contract address.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool);\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool);\n\n event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer);\n\n event ManagerChanged(address indexed account, address indexed newManager);\n}\n"},"OCIERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller\u0027s account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller\u0027s tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender\u0027s allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller\u0027s\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},"OCIERC777.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Interface of the ERC777Token standard as defined in the EIP.\n *\n * This contract uses the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let\n * token holders and recipients react to token movements by using setting implementers\n * for the associated interfaces in said registry. See {IERC1820Registry} and\n * {ERC1820Implementer}.\n */\ninterface IERC777 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the smallest part of the token that is not divisible. This\n * means all token operations (creation, movement and destruction) must have\n * amounts that are a multiple of this number.\n *\n * For most token contracts, this value will equal 1.\n */\n function granularity() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by an account (`owner`).\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller\u0027s account to `recipient`.\n *\n * If send or receive hooks are registered for the caller and `recipient`,\n * the corresponding functions will be called with `data` and empty\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function send(address recipient, uint256 amount, bytes calldata data) external;\n\n /**\n * @dev Destroys `amount` tokens from the caller\u0027s account, reducing the\n * total supply.\n *\n * If a send hook is registered for the caller, the corresponding function\n * will be called with `data` and empty `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n */\n function burn(uint256 amount, bytes calldata data) external;\n\n /**\n * @dev Returns true if an account is an operator of `tokenHolder`.\n * Operators can send and burn tokens on behalf of their owners. All\n * accounts are their own operator.\n *\n * See {operatorSend} and {operatorBurn}.\n */\n function isOperatorFor(address operator, address tokenHolder) external view returns (bool);\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor}.\n *\n * Emits an {AuthorizedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function authorizeOperator(address operator) external;\n\n /**\n * @dev Revoke an account\u0027s operator status for the caller.\n *\n * See {isOperatorFor} and {defaultOperators}.\n *\n * Emits a {RevokedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function revokeOperator(address operator) external;\n\n /**\n * @dev Returns the list of default operators. These accounts are operators\n * for all token holders, even if {authorizeOperator} was never called on\n * them.\n *\n * This list is immutable, but individual holders may revoke these via\n * {revokeOperator}, in which case {isOperatorFor} will return false.\n */\n function defaultOperators() external view returns (address[] memory);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must\n * be an operator of `sender`.\n *\n * If send or receive hooks are registered for `sender` and `recipient`,\n * the corresponding functions will be called with `data` and\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - `sender` cannot be the zero address.\n * - `sender` must have at least `amount` tokens.\n * - the caller must be an operator for `sender`.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the total supply.\n * The caller must be an operator of `account`.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `data` and `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n * - the caller must be an operator for `account`.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n event Sent(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);\n\n event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);\n\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n"},"OCIERC777Recipient.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.\n *\n * Accounts can be notified of {IERC777} tokens being sent to them by having a\n * contract implement this interface (contract holders can be their own\n * implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Recipient {\n /**\n * @dev Called by an {IERC777} token contract whenever tokens are being\n * moved or created into a registered account (`to`). The type of operation\n * is conveyed by `from` being the zero address or not.\n *\n * This call occurs _after_ the token contract\u0027s state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the post-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n"},"OCIERC777Sender.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Interface of the ERC777TokensSender standard as defined in the EIP.\n *\n * {IERC777} Token holders can be notified of operations performed on their\n * tokens by having a contract implement this interface (contract holders can be\n * their own implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Sender {\n /**\n * @dev Called by an {IERC777} token contract whenever a registered holder\u0027s\n * (`from`) tokens are about to be moved or destroyed. The type of operation\n * is conveyed by `to` being the zero address or not.\n *\n * This call occurs _before_ the token contract\u0027s state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n"},"OCReentrancyGuard.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\ncontract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot\u0027s contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler\u0027s defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction\u0027s gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor () internal {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and make it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n"},"OCSafeCast.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n\n/**\n * @dev Wrappers over Solidity\u0027s uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it\u0027s recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity\u0027s `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value \u003c 2**128, \"SafeCast: value doesn\\\u0027t fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity\u0027s `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value \u003c 2**64, \"SafeCast: value doesn\\\u0027t fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity\u0027s `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value \u003c 2**32, \"SafeCast: value doesn\\\u0027t fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity\u0027s `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value \u003c 2**16, \"SafeCast: value doesn\\\u0027t fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity\u0027s `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value \u003c 2**8, \"SafeCast: value doesn\\\u0027t fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value \u003e= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity\u0027s `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128) {\n require(value \u003e= -2**127 \u0026\u0026 value \u003c 2**127, \"SafeCast: value doesn\\\u0027t fit in 128 bits\");\n return int128(value);\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity\u0027s `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64) {\n require(value \u003e= -2**63 \u0026\u0026 value \u003c 2**63, \"SafeCast: value doesn\\\u0027t fit in 64 bits\");\n return int64(value);\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity\u0027s `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32) {\n require(value \u003e= -2**31 \u0026\u0026 value \u003c 2**31, \"SafeCast: value doesn\\\u0027t fit in 32 bits\");\n return int32(value);\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity\u0027s `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16) {\n require(value \u003e= -2**15 \u0026\u0026 value \u003c 2**15, \"SafeCast: value doesn\\\u0027t fit in 16 bits\");\n return int16(value);\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity\u0027s `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8) {\n require(value \u003e= -2**7 \u0026\u0026 value \u003c 2**7, \"SafeCast: value doesn\\\u0027t fit in 8 bits\");\n return int8(value);\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n require(value \u003c 2**255, \"SafeCast: value doesn\u0027t fit in an int256\");\n return int256(value);\n }\n}\n"},"OCSafeMath.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\n/**\n * @dev Wrappers over Solidity\u0027s arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it\u0027s recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity\u0027s `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c \u003e= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity\u0027s `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity\u0027s `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b \u003c= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity\u0027s `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring \u0027a\u0027 not being zero, but the\n // benefit is lost if \u0027b\u0027 is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity\u0027s `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity\u0027s `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b \u003e 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn\u0027t hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity\u0027s `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity\u0027s `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n"},"OEPAccessControl.sol":{"content":"pragma solidity ^0.6.0;\n\nimport \"./OEPEnumerableSet.sol\";\nimport \"./OEPAddress.sol\";\nimport \"./OEPContext.sol\";\nimport \"./OEPInitializable.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, _msgSender()));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role\u0027s admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n */\nabstract contract AccessControlUpgradeSafe is Initializable, ContextUpgradeSafe {\n function __AccessControl_init() internal initializer {\n __Context_init_unchained();\n __AccessControl_init_unchained();\n }\n\n function __AccessControl_init_unchained() internal initializer {\n\n\n }\n\n using EnumerableSet for EnumerableSet.AddressSet;\n using Address for address;\n\n struct RoleData {\n EnumerableSet.AddressSet members;\n bytes32 adminRole;\n }\n\n mapping (bytes32 =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view returns (bool) {\n return _roles[role].members.contains(account);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view returns (uint256) {\n return _roles[role].members.length();\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view returns (address) {\n return _roles[role].members.at(index);\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role\u0027s admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``\u0027s admin role.\n */\n function grantRole(bytes32 role, address account) public virtual {\n require(hasRole(_roles[role].adminRole, _msgSender()), \"AccessControl: sender must be an admin to grant\");\n\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``\u0027s admin role.\n */\n function revokeRole(bytes32 role, address account) public virtual {\n require(hasRole(_roles[role].adminRole, _msgSender()), \"AccessControl: sender must be an admin to revoke\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function\u0027s\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) public virtual {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn\u0027t perform any\n * checks on the calling account.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``\u0027s admin role.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n _roles[role].adminRole = adminRole;\n }\n\n function _grantRole(bytes32 role, address account) private {\n if (_roles[role].members.add(account)) {\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n function _revokeRole(bytes32 role, address account) private {\n if (_roles[role].members.remove(account)) {\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n\n uint256[49] private __gap;\n}\n"},"OEPAddress.sol":{"content":"pragma solidity ^0.6.2;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256(\u0027\u0027)`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly { codehash := extcodehash(account) }\n return (codehash != accountHash \u0026\u0026 codehash != 0x0);\n }\n\n /**\n * @dev Replacement for Solidity\u0027s `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-low-level-calls, avoid-call-value\n (bool success, ) = recipient.call{ value: amount }(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n"},"OEPContext.sol":{"content":"pragma solidity ^0.6.0;\nimport \"./OEPInitializable.sol\";\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract ContextUpgradeSafe is Initializable {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n\n function __Context_init() internal initializer {\n __Context_init_unchained();\n }\n\n function __Context_init_unchained() internal initializer {\n\n\n }\n\n\n function _msgSender() internal view virtual returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n\n uint256[50] private __gap;\n}\n"},"OEPEnumerableSet.sol":{"content":"pragma solidity ^0.6.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`\n * (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping (bytes32 =\u003e uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value\u0027s index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) { // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as \u0027swap and pop\u0027).\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs\n // so rarely, we still do the swap anyway to avoid the gas cost of adding an \u0027if\u0027 statement.\n\n bytes32 lastvalue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastvalue;\n // Update the index for the moved value\n set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n require(set._values.length \u003e index, \"EnumerableSet: index out of bounds\");\n return set._values[index];\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(value)));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(value)));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(value)));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint256(_at(set._inner, index)));\n }\n\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n}\n"},"OEPInitializable.sol":{"content":"pragma solidity \u003e=0.4.24 \u003c0.7.0;\n\n\n/**\n * @title Initializable\n *\n * @dev Helper contract to support initializer functions. To use it, replace\n * the constructor with a function that has the `initializer` modifier.\n * WARNING: Unlike constructors, initializer functions must be manually\n * invoked. This applies both to deploying an Initializable contract, as well\n * as extending an Initializable contract via inheritance.\n * WARNING: When used with inheritance, manual care must be taken to not invoke\n * a parent initializer twice, or ensure that all initializers are idempotent,\n * because this is not dealt with automatically as with constructors.\n */\ncontract Initializable {\n\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private initializing;\n\n /**\n * @dev Modifier to use in the initializer function of a contract.\n */\n modifier initializer() {\n require(initializing || isConstructor() || !initialized, \"Contract instance has already been initialized\");\n\n bool isTopLevelCall = !initializing;\n if (isTopLevelCall) {\n initializing = true;\n initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n initializing = false;\n }\n }\n\n /// @dev Returns true if and only if the function is running in the constructor\n function isConstructor() private view returns (bool) {\n // extcodesize checks the size of the code stored in an address, and\n // address returns the current address. Since the code is still not\n // deployed when running a constructor, any checks on its code size will\n // yield zero, making it an effective way to detect if a contract is\n // under construction or not.\n address self = address(this);\n uint256 cs;\n assembly { cs := extcodesize(self) }\n return cs == 0;\n }\n\n // Reserved storage space to allow for layout changes in the future.\n uint256[50] private ______gap;\n}\n"},"OEPOwnable.sol":{"content":"pragma solidity ^0.6.0;\n\nimport \"./OEPContext.sol\";\nimport \"./OEPInitializable.sol\";\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract OwnableUpgradeSafe is Initializable, ContextUpgradeSafe {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n\n function __Ownable_init() internal initializer {\n __Context_init_unchained();\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal initializer {\n\n\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n\n }\n\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(_owner == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n emit OwnershipTransferred(_owner, address(0));\n _owner = address(0);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n\n uint256[49] private __gap;\n}\n"},"PartialDifferences.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n PartialDifferences.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Dmytro Stebaiev\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"./MathUtils.sol\";\nimport \"./FractionUtils.sol\";\n\n/**\n * @title Partial Differences Library\n * @dev This library contains functions to manage Partial Differences data\n * structure. Partial Differences is an array of value differences over time.\n *\n * For example: assuming an array [3, 6, 3, 1, 2], partial differences can\n * represent this array as [_, 3, -3, -2, 1].\n *\n * This data structure allows adding values on an open interval with O(1)\n * complexity.\n *\n * For example: add +5 to [3, 6, 3, 1, 2] starting from the second element (3),\n * instead of performing [3, 6, 3+5, 1+5, 2+5] partial differences allows\n * performing [_, 3, -3+5, -2, 1]. The original array can be restored by\n * adding values from partial differences.\n */\nlibrary PartialDifferences {\n using SafeMath for uint;\n using MathUtils for uint;\n\n struct Sequence {\n // month =\u003e diff\n mapping (uint =\u003e uint) addDiff;\n // month =\u003e diff\n mapping (uint =\u003e uint) subtractDiff;\n // month =\u003e value\n mapping (uint =\u003e uint) value;\n\n uint firstUnprocessedMonth;\n uint lastChangedMonth;\n }\n\n struct Value {\n // month =\u003e diff\n mapping (uint =\u003e uint) addDiff;\n // month =\u003e diff\n mapping (uint =\u003e uint) subtractDiff;\n\n uint value;\n uint firstUnprocessedMonth;\n uint lastChangedMonth;\n }\n\n // functions for sequence\n\n function addToSequence(Sequence storage sequence, uint diff, uint month) internal {\n require(sequence.firstUnprocessedMonth \u003c= month, \"Cannot add to the past\");\n if (sequence.firstUnprocessedMonth == 0) {\n sequence.firstUnprocessedMonth = month;\n }\n sequence.addDiff[month] = sequence.addDiff[month].add(diff);\n if (sequence.lastChangedMonth != month) {\n sequence.lastChangedMonth = month;\n }\n }\n\n function subtractFromSequence(Sequence storage sequence, uint diff, uint month) internal {\n require(sequence.firstUnprocessedMonth \u003c= month, \"Cannot subtract from the past\");\n if (sequence.firstUnprocessedMonth == 0) {\n sequence.firstUnprocessedMonth = month;\n }\n sequence.subtractDiff[month] = sequence.subtractDiff[month].add(diff);\n if (sequence.lastChangedMonth != month) {\n sequence.lastChangedMonth = month;\n }\n }\n\n function getAndUpdateValueInSequence(Sequence storage sequence, uint month) internal returns (uint) {\n if (sequence.firstUnprocessedMonth == 0) {\n return 0;\n }\n\n if (sequence.firstUnprocessedMonth \u003c= month) {\n for (uint i = sequence.firstUnprocessedMonth; i \u003c= month; ++i) {\n uint nextValue = sequence.value[i.sub(1)].add(sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]);\n if (sequence.value[i] != nextValue) {\n sequence.value[i] = nextValue;\n }\n if (sequence.addDiff[i] \u003e 0) {\n delete sequence.addDiff[i];\n }\n if (sequence.subtractDiff[i] \u003e 0) {\n delete sequence.subtractDiff[i];\n }\n }\n sequence.firstUnprocessedMonth = month.add(1);\n }\n\n return sequence.value[month];\n }\n\n function reduceSequence(\n Sequence storage sequence,\n FractionUtils.Fraction memory reducingCoefficient,\n uint month) internal\n {\n require(month.add(1) \u003e= sequence.firstUnprocessedMonth, \"Can\u0027t reduce value in the past\");\n require(\n reducingCoefficient.numerator \u003c= reducingCoefficient.denominator,\n \"Increasing of values is not implemented\");\n if (sequence.firstUnprocessedMonth == 0) {\n return;\n }\n uint value = getAndUpdateValueInSequence(sequence, month);\n if (value.approximatelyEqual(0)) {\n return;\n }\n\n sequence.value[month] = sequence.value[month]\n .mul(reducingCoefficient.numerator)\n .div(reducingCoefficient.denominator);\n\n for (uint i = month.add(1); i \u003c= sequence.lastChangedMonth; ++i) {\n sequence.subtractDiff[i] = sequence.subtractDiff[i]\n .mul(reducingCoefficient.numerator)\n .div(reducingCoefficient.denominator);\n }\n }\n\n // functions for value\n\n function addToValue(Value storage sequence, uint diff, uint month) internal {\n require(sequence.firstUnprocessedMonth \u003c= month, \"Cannot add to the past\");\n if (sequence.firstUnprocessedMonth == 0) {\n sequence.firstUnprocessedMonth = month;\n sequence.lastChangedMonth = month;\n }\n if (month \u003e sequence.lastChangedMonth) {\n sequence.lastChangedMonth = month;\n }\n\n if (month \u003e= sequence.firstUnprocessedMonth) {\n sequence.addDiff[month] = sequence.addDiff[month].add(diff);\n } else {\n sequence.value = sequence.value.add(diff);\n }\n }\n\n function subtractFromValue(Value storage sequence, uint diff, uint month) internal {\n require(sequence.firstUnprocessedMonth \u003c= month.add(1), \"Cannot subtract from the past\");\n if (sequence.firstUnprocessedMonth == 0) {\n sequence.firstUnprocessedMonth = month;\n sequence.lastChangedMonth = month;\n }\n if (month \u003e sequence.lastChangedMonth) {\n sequence.lastChangedMonth = month;\n }\n\n if (month \u003e= sequence.firstUnprocessedMonth) {\n sequence.subtractDiff[month] = sequence.subtractDiff[month].add(diff);\n } else {\n sequence.value = sequence.value.boundedSub(diff);\n }\n }\n\n function getAndUpdateValue(Value storage sequence, uint month) internal returns (uint) {\n require(\n month.add(1) \u003e= sequence.firstUnprocessedMonth,\n \"Cannot calculate value in the past\");\n if (sequence.firstUnprocessedMonth == 0) {\n return 0;\n }\n\n if (sequence.firstUnprocessedMonth \u003c= month) {\n for (uint i = sequence.firstUnprocessedMonth; i \u003c= month; ++i) {\n uint newValue = sequence.value.add(sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]);\n if (sequence.value != newValue) {\n sequence.value = newValue;\n }\n if (sequence.addDiff[i] \u003e 0) {\n delete sequence.addDiff[i];\n }\n if (sequence.subtractDiff[i] \u003e 0) {\n delete sequence.subtractDiff[i];\n }\n }\n sequence.firstUnprocessedMonth = month.add(1);\n }\n\n return sequence.value;\n }\n\n function reduceValue(\n Value storage sequence,\n uint amount,\n uint month)\n internal returns (FractionUtils.Fraction memory)\n {\n require(month.add(1) \u003e= sequence.firstUnprocessedMonth, \"Cannot reduce value in the past\");\n if (sequence.firstUnprocessedMonth == 0) {\n return FractionUtils.createFraction(0);\n }\n uint value = getAndUpdateValue(sequence, month);\n if (value.approximatelyEqual(0)) {\n return FractionUtils.createFraction(0);\n }\n\n uint _amount = amount;\n if (value \u003c amount) {\n _amount = value;\n }\n\n FractionUtils.Fraction memory reducingCoefficient =\n FractionUtils.createFraction(value.boundedSub(_amount), value);\n reduceValueByCoefficient(sequence, reducingCoefficient, month);\n return reducingCoefficient;\n }\n\n function reduceValueByCoefficient(\n Value storage sequence,\n FractionUtils.Fraction memory reducingCoefficient,\n uint month)\n internal\n {\n reduceValueByCoefficientAndUpdateSumIfNeeded(\n sequence,\n sequence,\n reducingCoefficient,\n month,\n false);\n }\n\n function reduceValueByCoefficientAndUpdateSum(\n Value storage sequence,\n Value storage sumSequence,\n FractionUtils.Fraction memory reducingCoefficient,\n uint month) internal\n {\n reduceValueByCoefficientAndUpdateSumIfNeeded(\n sequence,\n sumSequence,\n reducingCoefficient,\n month,\n true);\n }\n\n function reduceValueByCoefficientAndUpdateSumIfNeeded(\n Value storage sequence,\n Value storage sumSequence,\n FractionUtils.Fraction memory reducingCoefficient,\n uint month,\n bool hasSumSequence) internal\n {\n require(month.add(1) \u003e= sequence.firstUnprocessedMonth, \"Cannot reduce value in the past\");\n if (hasSumSequence) {\n require(month.add(1) \u003e= sumSequence.firstUnprocessedMonth, \"Cannot reduce value in the past\");\n }\n require(\n reducingCoefficient.numerator \u003c= reducingCoefficient.denominator,\n \"Increasing of values is not implemented\");\n if (sequence.firstUnprocessedMonth == 0) {\n return;\n }\n uint value = getAndUpdateValue(sequence, month);\n if (value.approximatelyEqual(0)) {\n return;\n }\n\n uint newValue = sequence.value.mul(reducingCoefficient.numerator).div(reducingCoefficient.denominator);\n if (hasSumSequence) {\n subtractFromValue(sumSequence, sequence.value.boundedSub(newValue), month);\n }\n sequence.value = newValue;\n\n for (uint i = month.add(1); i \u003c= sequence.lastChangedMonth; ++i) {\n uint newDiff = sequence.subtractDiff[i]\n .mul(reducingCoefficient.numerator)\n .div(reducingCoefficient.denominator);\n if (hasSumSequence) {\n sumSequence.subtractDiff[i] = sumSequence.subtractDiff[i]\n .boundedSub(sequence.subtractDiff[i].boundedSub(newDiff));\n }\n sequence.subtractDiff[i] = newDiff;\n }\n }\n\n function clear(Value storage sequence) internal {\n for (uint i = sequence.firstUnprocessedMonth; i \u003c= sequence.lastChangedMonth; ++i) {\n if (sequence.addDiff[i] \u003e 0) {\n delete sequence.addDiff[i];\n }\n if (sequence.subtractDiff[i] \u003e 0) {\n delete sequence.subtractDiff[i];\n }\n }\n if (sequence.value \u003e 0) {\n delete sequence.value;\n }\n if (sequence.firstUnprocessedMonth \u003e 0) {\n delete sequence.firstUnprocessedMonth;\n }\n if (sequence.lastChangedMonth \u003e 0) {\n delete sequence.lastChangedMonth;\n }\n }\n}"},"Permissions.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n Permissions.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Artem Payvin\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"./OCSafeMath.sol\";\nimport \"./OEPAccessControl.sol\";\n\nimport \"./ContractManager.sol\";\n\n\n/**\n * @title Permissions - connected module for Upgradeable approach, knows ContractManager\n * @author Artem Payvin\n */\ncontract Permissions is AccessControlUpgradeSafe {\n using SafeMath for uint;\n using Address for address;\n \n ContractManager public contractManager;\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(_isOwner(), \"Caller is not the owner\");\n _;\n }\n\n modifier onlyAdmin() {\n require(_isAdmin(msg.sender), \"Caller is not an admin\");\n _;\n }\n\n /**\n * @dev allow - throws if called by any account and contract other than the owner\n * or `contractName` contract\n * @param contractName - human readable name of contract\n */\n modifier allow(string memory contractName) {\n require(\n contractManager.contracts(keccak256(abi.encodePacked(contractName))) == msg.sender || _isOwner(),\n \"Message sender is invalid\");\n _;\n }\n\n modifier allowTwo(string memory contractName1, string memory contractName2) {\n require(\n contractManager.contracts(keccak256(abi.encodePacked(contractName1))) == msg.sender ||\n contractManager.contracts(keccak256(abi.encodePacked(contractName2))) == msg.sender ||\n _isOwner(),\n \"Message sender is invalid\");\n _;\n }\n\n modifier allowThree(string memory contractName1, string memory contractName2, string memory contractName3) {\n require(\n contractManager.contracts(keccak256(abi.encodePacked(contractName1))) == msg.sender ||\n contractManager.contracts(keccak256(abi.encodePacked(contractName2))) == msg.sender ||\n contractManager.contracts(keccak256(abi.encodePacked(contractName3))) == msg.sender ||\n _isOwner(),\n \"Message sender is invalid\");\n _;\n }\n\n function initialize(address contractManagerAddress) public virtual initializer {\n AccessControlUpgradeSafe.__AccessControl_init();\n _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\n _setContractManager(contractManagerAddress);\n }\n\n function _isOwner() internal view returns (bool) {\n return hasRole(DEFAULT_ADMIN_ROLE, msg.sender);\n }\n\n function _isAdmin(address account) internal view returns (bool) {\n address skaleManagerAddress = contractManager.contracts(keccak256(abi.encodePacked(\"SkaleManager\")));\n if (skaleManagerAddress != address(0)) {\n AccessControlUpgradeSafe skaleManager = AccessControlUpgradeSafe(skaleManagerAddress);\n return skaleManager.hasRole(keccak256(\"ADMIN_ROLE\"), account) || _isOwner();\n } else {\n return _isOwner();\n }\n }\n\n function _setContractManager(address contractManagerAddress) private {\n require(contractManagerAddress != address(0), \"ContractManager address is not set\");\n require(contractManagerAddress.isContract(), \"Address is not contract\");\n contractManager = ContractManager(contractManagerAddress);\n }\n}\n"},"Punisher.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n Punisher.sol - SKALE Manager\n Copyright (C) 2019-Present SKALE Labs\n @author Dmytro Stebaiev\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"./OCSafeMath.sol\";\n\nimport \"./Permissions.sol\";\nimport \"./ILocker.sol\";\n\nimport \"./ValidatorService.sol\";\nimport \"./DelegationController.sol\";\n\n/**\n * @title Punisher\n * @dev This contract handles all slashing and forgiving operations.\n */\ncontract Punisher is Permissions, ILocker {\n\n /**\n * @dev Emitted when a slashing condition occurs.\n */\n event Slash(\n uint validatorId,\n uint amount\n );\n\n /**\n * @dev Emitted when a forgive condition occurs.\n */\n event Forgive(\n address wallet,\n uint amount\n );\n\n // holder =\u003e tokens\n mapping (address =\u003e uint) private _locked;\n\n /**\n * @dev Executes slashing on a validator and its delegations by an `amount`\n * of tokens. Currently, SkaleDKG is the only service allowed to execute\n * slashing.\n *\n * Emits a Slash event.\n *\n * @param validatorId uint validator to be slashed\n * @param amount uint slashed amount\n */\n function slash(uint validatorId, uint amount) external allow(\"SkaleDKG\") {\n ValidatorService validatorService = ValidatorService(contractManager.getContract(\"ValidatorService\"));\n DelegationController delegationController = DelegationController(\n contractManager.getContract(\"DelegationController\"));\n\n require(validatorService.validatorExists(validatorId), \"Validator does not exist\");\n\n delegationController.confiscate(validatorId, amount);\n\n emit Slash(validatorId, amount);\n }\n\n /**\n * @dev Allows the Owner to forgive a slashing condition.\n *\n * Emits a Forgive event.\n *\n * @param holder address of the slashed\n * @param amount uint amount to be forgiven\n */\n function forgive(address holder, uint amount) external onlyAdmin {\n DelegationController delegationController = DelegationController(\n contractManager.getContract(\"DelegationController\"));\n\n require(!delegationController.hasUnprocessedSlashes(holder), \"Not all slashes were calculated\");\n\n if (amount \u003e _locked[holder]) {\n delete _locked[holder];\n } else {\n _locked[holder] = _locked[holder].sub(amount);\n }\n\n emit Forgive(holder, amount);\n }\n\n /**\n * @dev See ILocker-getAndUpdateLockedAmount\n */\n function getAndUpdateLockedAmount(address wallet) external override returns (uint) {\n return _getAndUpdateLockedAmount(wallet);\n }\n\n /**\n * @dev See ILocker-getAndUpdateForbiddenForDelegationAmount\n */\n function getAndUpdateForbiddenForDelegationAmount(address wallet) external override returns (uint) {\n return _getAndUpdateLockedAmount(wallet);\n }\n\n function handleSlash(address holder, uint amount) external allow(\"DelegationController\") {\n _locked[holder] = _locked[holder].add(amount);\n }\n\n function initialize(address contractManagerAddress) public override initializer {\n Permissions.initialize(contractManagerAddress);\n }\n\n // private\n\n function _getAndUpdateLockedAmount(address wallet) private returns (uint) {\n DelegationController delegationController = DelegationController(\n contractManager.getContract(\"DelegationController\"));\n\n delegationController.processAllSlashes(wallet);\n return _locked[wallet];\n }\n\n}"},"SkaleToken.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n SkaleToken.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Artem Payvin\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"./OCSafeMath.sol\";\nimport \"./OCReentrancyGuard.sol\";\n\nimport \"./ERC777.sol\";\n\nimport \"./Permissions.sol\";\nimport \"./IDelegatableToken.sol\";\nimport \"./Punisher.sol\";\nimport \"./TokenState.sol\";\n\n\n/**\n * @title SkaleToken is ERC777 Token implementation, also this contract in skale\n * manager system\n */\ncontract SkaleToken is ERC777, Permissions, ReentrancyGuard, IDelegatableToken {\n using SafeMath for uint;\n\n string public constant NAME = \"SKALE\";\n\n string public constant SYMBOL = \"SKL\";\n\n uint public constant DECIMALS = 18;\n\n uint public constant CAP = 7 * 1e9 * (10 ** DECIMALS); // the maximum amount of tokens that can ever be created\n\n constructor(address contractsAddress, address[] memory defOps) public\n ERC777(\"SKALE\", \"SKL\", defOps)\n {\n Permissions.initialize(contractsAddress);\n }\n\n /**\n * @dev mint - create some amount of token and transfer it to the specified address\n * @param account - address where some amount of token would be created\n * @param amount - amount of tokens to mine\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @return returns success of function call.\n */\n function mint(\n address account,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n )\n external\n allow(\"SkaleManager\")\n //onlyAuthorized\n returns (bool)\n {\n require(amount \u003c= CAP.sub(totalSupply()), \"Amount is too big\");\n _mint(\n account,\n amount,\n userData,\n operatorData\n );\n\n return true;\n }\n\n function getAndUpdateDelegatedAmount(address wallet) external override returns (uint) {\n return DelegationController(contractManager.getContract(\"DelegationController\"))\n .getAndUpdateDelegatedAmount(wallet);\n }\n\n function getAndUpdateSlashedAmount(address wallet) external override returns (uint) {\n return Punisher(contractManager.getContract(\"Punisher\")).getAndUpdateLockedAmount(wallet);\n }\n\n function getAndUpdateLockedAmount(address wallet) public override returns (uint) {\n return TokenState(contractManager.getContract(\"TokenState\")).getAndUpdateLockedAmount(wallet);\n }\n\n // internal\n\n function _beforeTokenTransfer(\n address, // operator\n address from,\n address, // to\n uint256 tokenId)\n internal override\n {\n uint locked = getAndUpdateLockedAmount(from);\n if (locked \u003e 0) {\n require(balanceOf(from) \u003e= locked.add(tokenId), \"Token should be unlocked for transferring\");\n }\n }\n\n function _callTokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal override nonReentrant {\n super._callTokensToSend(operator, from, to, amount, userData, operatorData);\n }\n\n function _callTokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal override nonReentrant {\n super._callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck);\n }\n\n // we have to override _msgData() and _msgSender() functions because of collision in Context and ContextUpgradeSafe\n\n function _msgData() internal view override(Context, ContextUpgradeSafe) returns (bytes memory) {\n return Context._msgData();\n }\n\n function _msgSender() internal view override(Context, ContextUpgradeSafe) returns (address payable) {\n return Context._msgSender();\n }\n}\n"},"StringUtils.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n StringUtils.sol - SKALE Manager\n Copyright (C) 2018-Present SKALE Labs\n @author Vadim Yavorsky\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"./OCSafeMath.sol\";\n\n\nlibrary StringUtils {\n using SafeMath for uint;\n\n function strConcat(string memory a, string memory b) internal pure returns (string memory) {\n bytes memory _ba = bytes(a);\n bytes memory _bb = bytes(b);\n\n string memory ab = new string(_ba.length.add(_bb.length));\n bytes memory strBytes = bytes(ab);\n uint k = 0;\n uint i = 0;\n for (i = 0; i \u003c _ba.length; i++) {\n strBytes[k++] = _ba[i];\n }\n for (i = 0; i \u003c _bb.length; i++) {\n strBytes[k++] = _bb[i];\n }\n return string(strBytes);\n }\n\n function uint2str(uint i) internal pure returns (string memory) {\n if (i == 0) {\n return \"0\";\n }\n uint j = i;\n uint _i = i;\n uint len;\n while (j != 0) {\n len++;\n j /= 10;\n }\n bytes memory bstr = new bytes(len);\n uint k = len.sub(1);\n while (_i != 0) {\n bstr[k--] = byte(uint8(48 + _i % 10));\n _i /= 10;\n }\n return string(bstr);\n }\n}"},"TimeHelpers.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n TimeHelpers.sol - SKALE Manager\n Copyright (C) 2019-Present SKALE Labs\n @author Dmytro Stebaiev\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"./OCSafeMath.sol\";\n\nimport \"./BokkyPooBahsDateTimeLibrary.sol\";\n\n/**\n * @title TimeHelpers\n * @dev The contract performs time operations.\n *\n * These functions are used to calculate monthly and Proof of Use epochs.\n */\ncontract TimeHelpers {\n using SafeMath for uint;\n\n uint constant private _ZERO_YEAR = 2020;\n\n function calculateProofOfUseLockEndTime(uint month, uint lockUpPeriodDays) external view returns (uint timestamp) {\n timestamp = BokkyPooBahsDateTimeLibrary.addDays(monthToTimestamp(month), lockUpPeriodDays);\n }\n\n function addMonths(uint fromTimestamp, uint n) external pure returns (uint) {\n return BokkyPooBahsDateTimeLibrary.addMonths(fromTimestamp, n);\n }\n\n function getCurrentMonth() external view virtual returns (uint) {\n return timestampToMonth(now);\n }\n\n function timestampToMonth(uint timestamp) public view virtual returns (uint) {\n uint year;\n uint month;\n (year, month, ) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp);\n require(year \u003e= _ZERO_YEAR, \"Timestamp is too far in the past\");\n month = month.sub(1).add(year.sub(_ZERO_YEAR).mul(12));\n require(month \u003e 0, \"Timestamp is too far in the past\");\n return month;\n }\n\n function monthToTimestamp(uint month) public view virtual returns (uint timestamp) {\n uint year = _ZERO_YEAR;\n uint _month = month;\n year = year.add(_month.div(12));\n _month = _month.mod(12);\n _month = _month.add(1);\n return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, _month, 1);\n }\n}\n"},"TokenLaunchLocker.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n TokenLaunchLocker.sol - SKALE Manager\n Copyright (C) 2019-Present SKALE Labs\n @author Dmytro Stebaiev\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\n\nimport \"./OCSafeMath.sol\";\n\nimport \"./Permissions.sol\";\nimport \"./ILocker.sol\";\nimport \"./ConstantsHolder.sol\";\nimport \"./MathUtils.sol\";\n\nimport \"./DelegationController.sol\";\nimport \"./TimeHelpers.sol\";\nimport \"./PartialDifferences.sol\";\n\n\ncontract TokenLaunchLocker is Permissions, ILocker {\n using MathUtils for uint;\n using PartialDifferences for PartialDifferences.Value;\n\n /**\n * @dev Emitted when an `amount` is unlocked.\n */\n event Unlocked(\n address holder,\n uint amount\n );\n\n /**\n * @dev Emitted when an `amount` is locked.\n */\n event Locked(\n address holder,\n uint amount\n );\n\n struct DelegatedAmountAndMonth {\n uint delegated;\n uint month;\n }\n\n // holder =\u003e tokens\n mapping (address =\u003e uint) private _locked;\n\n // holder =\u003e tokens\n mapping (address =\u003e PartialDifferences.Value) private _delegatedAmount;\n\n mapping (address =\u003e DelegatedAmountAndMonth) private _totalDelegatedAmount;\n\n // delegationId =\u003e tokens\n mapping (uint =\u003e uint) private _delegationAmount;\n\n function lock(address holder, uint amount) external allow(\"TokenLaunchManager\") {\n _locked[holder] = _locked[holder].add(amount);\n\n emit Locked(holder, amount);\n }\n\n function handleDelegationAdd(\n address holder, uint delegationId, uint amount, uint month)\n external allow(\"DelegationController\")\n {\n if (_locked[holder] \u003e 0) {\n TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract(\"TimeHelpers\"));\n\n uint currentMonth = timeHelpers.getCurrentMonth();\n uint fromLocked = amount;\n uint locked = _locked[holder].boundedSub(_getAndUpdateDelegatedAmount(holder, currentMonth));\n if (fromLocked \u003e locked) {\n fromLocked = locked;\n }\n if (fromLocked \u003e 0) {\n require(_delegationAmount[delegationId] == 0, \"Delegation was already added\");\n _addToDelegatedAmount(holder, fromLocked, month);\n _addToTotalDelegatedAmount(holder, fromLocked, month);\n _delegationAmount[delegationId] = fromLocked;\n }\n }\n }\n\n function handleDelegationRemoving(\n address holder,\n uint delegationId,\n uint month)\n external allow(\"DelegationController\")\n {\n if (_delegationAmount[delegationId] \u003e 0) {\n if (_locked[holder] \u003e 0) {\n _removeFromDelegatedAmount(holder, _delegationAmount[delegationId], month);\n }\n delete _delegationAmount[delegationId];\n }\n }\n\n function getAndUpdateLockedAmount(address wallet) external override returns (uint) {\n if (_locked[wallet] \u003e 0) {\n DelegationController delegationController = DelegationController(\n contractManager.getContract(\"DelegationController\"));\n TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract(\"TimeHelpers\"));\n ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract(\"ConstantsHolder\"));\n\n uint currentMonth = timeHelpers.getCurrentMonth();\n if (_totalDelegatedSatisfiesProofOfUserCondition(wallet) \u0026\u0026\n timeHelpers.calculateProofOfUseLockEndTime(\n _totalDelegatedAmount[wallet].month,\n constantsHolder.proofOfUseLockUpPeriodDays()\n ) \u003c= now) {\n _unlock(wallet);\n return 0;\n } else {\n uint lockedByDelegationController = _getAndUpdateDelegatedAmount(wallet, currentMonth)\n .add(delegationController.getLockedInPendingDelegations(wallet));\n if (_locked[wallet] \u003e lockedByDelegationController) {\n return _locked[wallet].boundedSub(lockedByDelegationController);\n } else {\n return 0;\n }\n }\n } else {\n return 0;\n }\n }\n\n function getAndUpdateForbiddenForDelegationAmount(address) external override returns (uint) {\n return 0;\n }\n\n function initialize(address contractManagerAddress) public override initializer {\n Permissions.initialize(contractManagerAddress);\n }\n\n // private\n\n function _getAndUpdateDelegatedAmount(address holder, uint currentMonth) private returns (uint) {\n return _delegatedAmount[holder].getAndUpdateValue(currentMonth);\n }\n\n function _addToDelegatedAmount(address holder, uint amount, uint month) private {\n _delegatedAmount[holder].addToValue(amount, month);\n }\n\n function _removeFromDelegatedAmount(address holder, uint amount, uint month) private {\n _delegatedAmount[holder].subtractFromValue(amount, month);\n }\n\n function _addToTotalDelegatedAmount(address holder, uint amount, uint month) private {\n require(\n _totalDelegatedAmount[holder].month == 0 || _totalDelegatedAmount[holder].month \u003c= month,\n \"Can\u0027t add to total delegated in the past\");\n\n // do not update counter if it is big enough\n // because it will override month value\n if (!_totalDelegatedSatisfiesProofOfUserCondition(holder)) {\n _totalDelegatedAmount[holder].delegated = _totalDelegatedAmount[holder].delegated.add(amount);\n _totalDelegatedAmount[holder].month = month;\n }\n }\n\n function _unlock(address holder) private {\n emit Unlocked(holder, _locked[holder]);\n delete _locked[holder];\n _deleteDelegatedAmount(holder);\n _deleteTotalDelegatedAmount(holder);\n }\n\n function _deleteDelegatedAmount(address holder) private {\n _delegatedAmount[holder].clear();\n }\n\n function _deleteTotalDelegatedAmount(address holder) private {\n delete _totalDelegatedAmount[holder].delegated;\n delete _totalDelegatedAmount[holder].month;\n }\n\n function _totalDelegatedSatisfiesProofOfUserCondition(address holder) private view returns (bool) {\n ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract(\"ConstantsHolder\"));\n\n return _totalDelegatedAmount[holder].delegated.mul(100) \u003e=\n _locked[holder].mul(constantsHolder.proofOfUseDelegationPercentage());\n }\n}"},"TokenState.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n TokenState.sol - SKALE Manager\n Copyright (C) 2019-Present SKALE Labs\n @author Dmytro Stebaiev\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\npragma experimental ABIEncoderV2;\n\nimport \"./Permissions.sol\";\nimport \"./DelegationController.sol\";\nimport \"./TimeHelpers.sol\";\nimport \"./ILocker.sol\";\n\n\n/**\n * @title Token State\n * @dev This contract manages lockers to control token transferability.\n *\n * See ILocker.\n */\ncontract TokenState is Permissions, ILocker {\n\n /**\n * @dev Emitted when a contract is added to the locker.\n */\n event LockerWasAdded(\n string locker\n );\n\n /**\n * @dev Emitted when a contract is removed from the locker.\n */\n event LockerWasRemoved(\n string locker\n );\n\n string[] private _lockers;\n\n /**\n * @dev Return and update the total locked amount of a given `holder`.\n *\n * @param holder address of the token holder\n * @return total locked amount\n */\n function getAndUpdateLockedAmount(address holder) external override returns (uint) {\n uint locked = 0;\n for (uint i = 0; i \u003c _lockers.length; ++i) {\n ILocker locker = ILocker(contractManager.getContract(_lockers[i]));\n locked = locked.add(locker.getAndUpdateLockedAmount(holder));\n }\n return locked;\n }\n\n /**\n * @dev Return and update the total locked and un-delegatable amount of a given `holder`.\n *\n * @param holder address of the token holder\n * @return amount total slashed amount (non-transferable and non-delegatable)\n */\n function getAndUpdateForbiddenForDelegationAmount(address holder) external override returns (uint amount) {\n uint forbidden = 0;\n for (uint i = 0; i \u003c _lockers.length; ++i) {\n ILocker locker = ILocker(contractManager.getContract(_lockers[i]));\n forbidden = forbidden.add(locker.getAndUpdateForbiddenForDelegationAmount(holder));\n }\n return forbidden;\n }\n\n /**\n * @dev Allows the Owner to remove a contract from the locker.\n *\n * Emits a LockerWasRemoved event.\n *\n * @param locker string name of contract to remove from locker\n */\n function removeLocker(string calldata locker) external onlyOwner {\n uint index;\n bytes32 hash = keccak256(abi.encodePacked(locker));\n for (index = 0; index \u003c _lockers.length; ++index) {\n if (keccak256(abi.encodePacked(_lockers[index])) == hash) {\n break;\n }\n }\n if (index \u003c _lockers.length) {\n if (index \u003c _lockers.length.sub(1)) {\n _lockers[index] = _lockers[_lockers.length.sub(1)];\n }\n delete _lockers[_lockers.length.sub(1)];\n _lockers.pop();\n emit LockerWasRemoved(locker);\n }\n }\n\n function initialize(address contractManagerAddress) public override initializer {\n Permissions.initialize(contractManagerAddress);\n addLocker(\"DelegationController\");\n addLocker(\"Punisher\");\n addLocker(\"TokenLaunchLocker\");\n }\n\n /**\n * @dev Allows the Owner to add a contract to the Locker.\n *\n * Emits a LockerWasAdded event.\n *\n * @param locker string name of contract to add to locker\n */\n function addLocker(string memory locker) public onlyOwner {\n _lockers.push(locker);\n emit LockerWasAdded(locker);\n }\n}\n"},"ValidatorService.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-only\n\n/*\n ValidatorService.sol - SKALE Manager\n Copyright (C) 2019-Present SKALE Labs\n @author Dmytro Stebaiev\n @author Artem Payvin\n @author Vadim Yavorsky\n\n SKALE Manager is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as published\n by the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n SKALE Manager is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with SKALE Manager. If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n*/\n\npragma solidity 0.6.10;\npragma experimental ABIEncoderV2;\n\nimport \"./OCSafeMath.sol\";\nimport \"./OCECDSA.sol\";\n\nimport \"./Permissions.sol\";\nimport \"./ConstantsHolder.sol\";\n\nimport \"./DelegationController.sol\";\n\n/**\n * @title ValidatorService\n * @dev This contract handles all validator operations including registration,\n * node management, validator-specific delegation parameters, and more.\n *\n * Validators register an address, and use this address to accept delegations and\n * register nodes.\n *\n */\ncontract ValidatorService is Permissions {\n\n using ECDSA for bytes32;\n\n struct Validator {\n string name;\n address validatorAddress;\n address requestedAddress;\n string description;\n uint feeRate;\n uint registrationTime;\n uint minimumDelegationAmount;\n bool acceptNewRequests;\n }\n\n /**\n * @dev Emitted when a validator registers.\n */\n event ValidatorRegistered(\n uint validatorId\n );\n\n /**\n * @dev Emitted when a validator address changes.\n */\n event ValidatorAddressChanged(\n uint validatorId,\n address newAddress\n );\n\n event ValidatorWasEnabled(\n uint validatorId\n );\n\n event ValidatorWasDisabled(\n uint validatorId\n );\n\n /**\n * @dev Emitted when a node address is linked to a validator.\n */\n event NodeAddressWasAdded(\n uint validatorId,\n address nodeAddress\n );\n\n /**\n * @dev Emitted when a node address is unlinked from a validator.\n */\n event NodeAddressWasRemoved(\n uint validatorId,\n address nodeAddress\n );\n\n mapping (uint =\u003e Validator) public validators;\n mapping (uint =\u003e bool) private _trustedValidators;\n uint[] public trustedValidatorsList;\n // address =\u003e validatorId\n mapping (address =\u003e uint) private _validatorAddressToId;\n // address =\u003e validatorId\n mapping (address =\u003e uint) private _nodeAddressToValidatorId;\n // validatorId =\u003e nodeAddress[]\n mapping (uint =\u003e address[]) private _nodeAddresses;\n uint public numberOfValidators;\n bool public useWhitelist;\n\n modifier checkValidatorExists(uint validatorId) {\n require(validatorExists(validatorId), \"Validator with such ID does not exist\");\n _;\n }\n\n /**\n * @dev Creates a new validator Id.\n *\n * Requirements:\n *\n * - sender must not already have registered a validator Id.\n * - fee rate must be between 0 - 1000‰. Note: per mille!\n *\n * Emits ValidatorRegistered event.\n *\n * @param name string\n * @param description string\n * @param feeRate uint Fee charged on delegations by the validator per mille\n * @param minimumDelegationAmount uint Minimum delegation amount accepted by the validator\n */\n function registerValidator(\n string calldata name,\n string calldata description,\n uint feeRate,\n uint minimumDelegationAmount\n )\n external\n returns (uint validatorId)\n {\n require(!validatorAddressExists(msg.sender), \"Validator with such address already exists\");\n require(feeRate \u003c 1000, \"Fee rate of validator should be lower than 100%\");\n validatorId = ++numberOfValidators;\n validators[validatorId] = Validator(\n name,\n msg.sender,\n address(0),\n description,\n feeRate,\n now,\n minimumDelegationAmount,\n true\n );\n _setValidatorAddress(validatorId, msg.sender);\n\n emit ValidatorRegistered(validatorId);\n }\n\n function enableValidator(uint validatorId) external checkValidatorExists(validatorId) onlyAdmin {\n require(!_trustedValidators[validatorId], \"Validator is already enabled\");\n _trustedValidators[validatorId] = true;\n trustedValidatorsList.push(validatorId);\n emit ValidatorWasEnabled(validatorId);\n }\n\n function disableValidator(uint validatorId) external checkValidatorExists(validatorId) onlyAdmin {\n require(_trustedValidators[validatorId], \"Validator is already disabled\");\n _trustedValidators[validatorId] = false;\n uint position = _find(trustedValidatorsList, validatorId);\n if (position \u003c trustedValidatorsList.length) {\n trustedValidatorsList[position] =\n trustedValidatorsList[trustedValidatorsList.length.sub(1)];\n }\n trustedValidatorsList.pop();\n emit ValidatorWasDisabled(validatorId);\n }\n\n /**\n * @dev Owner can disable the validator whitelist. Once turned off the\n * whitelist cannot be re-enabled.\n */\n function disableWhitelist() external onlyOwner {\n useWhitelist = false;\n }\n\n /**\n * @dev Allows a validator to request a new address.\n *\n * Requirements:\n *\n * - new address must not be null\n * - new address must not be already registered as a validator\n *\n * @param newValidatorAddress address\n */\n function requestForNewAddress(address newValidatorAddress) external {\n require(newValidatorAddress != address(0), \"New address cannot be null\");\n require(_validatorAddressToId[newValidatorAddress] == 0, \"Address already registered\");\n // check Validator Exist inside getValidatorId\n uint validatorId = getValidatorId(msg.sender);\n\n validators[validatorId].requestedAddress = newValidatorAddress;\n }\n\n function confirmNewAddress(uint validatorId)\n external\n checkValidatorExists(validatorId)\n {\n require(\n getValidator(validatorId).requestedAddress == msg.sender,\n \"The validator address cannot be changed because it is not the actual owner\"\n );\n delete validators[validatorId].requestedAddress;\n _setValidatorAddress(validatorId, msg.sender);\n\n emit ValidatorAddressChanged(validatorId, validators[validatorId].validatorAddress);\n }\n\n /**\n * @dev Links a given node address.\n *\n * Requirements:\n *\n * - the given signature must be valid.\n * - the address must not be assigned to a validator.\n *\n * Emits NodeAddressWasAdded event.\n *\n * @param nodeAddress address\n * @param sig bytes signature of validator Id by node operator.\n */\n function linkNodeAddress(address nodeAddress, bytes calldata sig) external {\n // check Validator Exist inside getValidatorId\n uint validatorId = getValidatorId(msg.sender);\n require(\n keccak256(abi.encodePacked(validatorId)).toEthSignedMessageHash().recover(sig) == nodeAddress,\n \"Signature is not pass\"\n );\n require(_validatorAddressToId[nodeAddress] == 0, \"Node address is a validator\");\n\n _addNodeAddress(validatorId, nodeAddress);\n emit NodeAddressWasAdded(validatorId, nodeAddress);\n }\n\n /**\n * @dev Unlinks a given node address from a validator.\n *\n * Emits NodeAddressWasRemoved event.\n *\n * @param nodeAddress address\n */\n function unlinkNodeAddress(address nodeAddress) external {\n // check Validator Exist inside getValidatorId\n uint validatorId = getValidatorId(msg.sender);\n\n _removeNodeAddress(validatorId, nodeAddress);\n emit NodeAddressWasRemoved(validatorId, nodeAddress);\n }\n\n function setValidatorMDA(uint minimumDelegationAmount) external {\n // check Validator Exist inside getValidatorId\n uint validatorId = getValidatorId(msg.sender);\n\n validators[validatorId].minimumDelegationAmount = minimumDelegationAmount;\n }\n\n /**\n * @dev Allows a validator to set a new validator name.\n *\n * @param newName string\n */\n function setValidatorName(string calldata newName) external {\n // check Validator Exist inside getValidatorId\n uint validatorId = getValidatorId(msg.sender);\n\n validators[validatorId].name = newName;\n }\n\n /**\n * @dev Allows a validator to set a new validator description.\n *\n * @param newDescription string\n */\n function setValidatorDescription(string calldata newDescription) external {\n // check Validator Exist inside getValidatorId\n uint validatorId = getValidatorId(msg.sender);\n\n validators[validatorId].description = newDescription;\n }\n\n /**\n * @dev Allows a validator to start accepting new delegation requests.\n *\n * Requirements:\n *\n * - validator must not have already enabled accepting new requests\n */\n function startAcceptingNewRequests() external {\n // check Validator Exist inside getValidatorId\n uint validatorId = getValidatorId(msg.sender);\n require(!isAcceptingNewRequests(validatorId), \"Accepting request is already enabled\");\n\n validators[validatorId].acceptNewRequests = true;\n }\n\n /**\n * @dev Allows a validator to stop accepting new delegation requests.\n *\n * Requirements:\n *\n * - validator must not have already stopped accepting new requests\n */\n function stopAcceptingNewRequests() external {\n // check Validator Exist inside getValidatorId\n uint validatorId = getValidatorId(msg.sender);\n require(isAcceptingNewRequests(validatorId), \"Accepting request is already disabled\");\n\n validators[validatorId].acceptNewRequests = false;\n }\n\n /**\n * @dev Returns the amount of validator bond.\n *\n * @param validatorId uint ID of validator to return the amount of locked funds\n * @return bondAmount uint the amount of self-delegated funds by the validator\n */\n function getAndUpdateBondAmount(uint validatorId)\n external\n returns (uint)\n {\n DelegationController delegationController = DelegationController(\n contractManager.getContract(\"DelegationController\")\n );\n return delegationController.getAndUpdateDelegatedByHolderToValidatorNow(\n getValidator(validatorId).validatorAddress,\n validatorId\n );\n }\n\n function getMyNodesAddresses() external view returns (address[] memory) {\n return getNodeAddresses(getValidatorId(msg.sender));\n }\n\n /**\n * @dev Returns a list of trusted validators.\n *\n * @return uint[] trusted validators\n */\n function getTrustedValidators() external view returns (uint[] memory) {\n return trustedValidatorsList;\n }\n\n function checkMinimumDelegation(uint validatorId, uint amount)\n external\n view\n checkValidatorExists(validatorId)\n allow(\"DelegationController\")\n returns (bool)\n {\n return validators[validatorId].minimumDelegationAmount \u003c= amount ? true : false;\n }\n\n function checkValidatorAddressToId(address validatorAddress, uint validatorId)\n external\n view\n returns (bool)\n {\n return getValidatorId(validatorAddress) == validatorId ? true : false;\n }\n\n function getValidatorIdByNodeAddress(address nodeAddress) external view returns (uint validatorId) {\n validatorId = _nodeAddressToValidatorId[nodeAddress];\n require(validatorId != 0, \"Node address is not assigned to a validator\");\n }\n\n\n function isAuthorizedValidator(uint validatorId) external view checkValidatorExists(validatorId) returns (bool) {\n return _trustedValidators[validatorId] || !useWhitelist;\n }\n\n function initialize(address contractManagerAddress) public override initializer {\n Permissions.initialize(contractManagerAddress);\n useWhitelist = true;\n }\n\n function getNodeAddresses(uint validatorId) public view returns (address[] memory) {\n return _nodeAddresses[validatorId];\n }\n\n function validatorExists(uint validatorId) public view returns (bool) {\n return validatorId \u003c= numberOfValidators \u0026\u0026 validatorId != 0;\n }\n\n function validatorAddressExists(address validatorAddress) public view returns (bool) {\n return _validatorAddressToId[validatorAddress] != 0;\n }\n\n function checkIfValidatorAddressExists(address validatorAddress) public view {\n require(validatorAddressExists(validatorAddress), \"Validator with given address does not exist\");\n }\n\n function getValidator(uint validatorId) public view checkValidatorExists(validatorId) returns (Validator memory) {\n return validators[validatorId];\n }\n\n function getValidatorId(address validatorAddress) public view returns (uint) {\n checkIfValidatorAddressExists(validatorAddress);\n return _validatorAddressToId[validatorAddress];\n }\n\n function isAcceptingNewRequests(uint validatorId) public view checkValidatorExists(validatorId) returns (bool) {\n return validators[validatorId].acceptNewRequests;\n }\n\n // private\n function _setValidatorAddress(uint validatorId, address validatorAddress) private {\n if (_validatorAddressToId[validatorAddress] == validatorId) {\n return;\n }\n require(_validatorAddressToId[validatorAddress] == 0, \"Address is in use by another validator\");\n address oldAddress = validators[validatorId].validatorAddress;\n delete _validatorAddressToId[oldAddress];\n _nodeAddressToValidatorId[validatorAddress] = validatorId;\n validators[validatorId].validatorAddress = validatorAddress;\n _validatorAddressToId[validatorAddress] = validatorId;\n }\n\n function _addNodeAddress(uint validatorId, address nodeAddress) private {\n if (_nodeAddressToValidatorId[nodeAddress] == validatorId) {\n return;\n }\n require(_nodeAddressToValidatorId[nodeAddress] == 0, \"Validator cannot override node address\");\n _nodeAddressToValidatorId[nodeAddress] = validatorId;\n _nodeAddresses[validatorId].push(nodeAddress);\n }\n\n function _removeNodeAddress(uint validatorId, address nodeAddress) private {\n require(_nodeAddressToValidatorId[nodeAddress] == validatorId,\n \"Validator does not have permissions to unlink node\");\n delete _nodeAddressToValidatorId[nodeAddress];\n for (uint i = 0; i \u003c _nodeAddresses[validatorId].length; ++i) {\n if (_nodeAddresses[validatorId][i] == nodeAddress) {\n if (i + 1 \u003c _nodeAddresses[validatorId].length) {\n _nodeAddresses[validatorId][i] =\n _nodeAddresses[validatorId][_nodeAddresses[validatorId].length.sub(1)];\n }\n delete _nodeAddresses[validatorId][_nodeAddresses[validatorId].length.sub(1)];\n _nodeAddresses[validatorId].pop();\n break;\n }\n }\n }\n\n function _find(uint[] memory array, uint index) private pure returns (uint) {\n uint i;\n for (i = 0; i \u003c array.length; i++) {\n if (array[i] == index) {\n return i;\n }\n }\n return array.length;\n }\n}\n"}}
File 2 of 8: ERC1820Registry
/* ERC1820 Pseudo-introspection Registry Contract * This standard defines a universal registry smart contract where any address (contract or regular account) can * register which interface it supports and which smart contract is responsible for its implementation. * * Written in 2019 by Jordi Baylina and Jacques Dafflon * * To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to * this software to the public domain worldwide. This software is distributed without any warranty. * * You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see * <http://creativecommons.org/publicdomain/zero/1.0/>. * * ███████╗██████╗ ██████╗ ██╗ █████╗ ██████╗ ██████╗ * ██╔════╝██╔══██╗██╔════╝███║██╔══██╗╚════██╗██╔═████╗ * █████╗ ██████╔╝██║ ╚██║╚█████╔╝ █████╔╝██║██╔██║ * ██╔══╝ ██╔══██╗██║ ██║██╔══██╗██╔═══╝ ████╔╝██║ * ███████╗██║ ██║╚██████╗ ██║╚█████╔╝███████╗╚██████╔╝ * ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚════╝ ╚══════╝ ╚═════╝ * * ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗ ██╗ * ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝ * ██████╔╝█████╗ ██║ ███╗██║███████╗ ██║ ██████╔╝ ╚████╔╝ * ██╔══██╗██╔══╝ ██║ ██║██║╚════██║ ██║ ██╔══██╗ ╚██╔╝ * ██║ ██║███████╗╚██████╔╝██║███████║ ██║ ██║ ██║ ██║ * ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ * */ pragma solidity 0.5.3; // IV is value needed to have a vanity address starting with '0x1820'. // IV: 53759 /// @dev The interface a contract MUST implement if it is the implementer of /// some (other) interface for any address other than itself. interface ERC1820ImplementerInterface { /// @notice Indicates whether the contract implements the interface 'interfaceHash' for the address 'addr' or not. /// @param interfaceHash keccak256 hash of the name of the interface /// @param addr Address for which the contract will implement the interface /// @return ERC1820_ACCEPT_MAGIC only if the contract implements 'interfaceHash' for the address 'addr'. function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32); } /// @title ERC1820 Pseudo-introspection Registry Contract /// @author Jordi Baylina and Jacques Dafflon /// @notice This contract is the official implementation of the ERC1820 Registry. /// @notice For more details, see https://eips.ethereum.org/EIPS/eip-1820 contract ERC1820Registry { /// @notice ERC165 Invalid ID. bytes4 constant internal INVALID_ID = 0xffffffff; /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`). bytes4 constant internal ERC165ID = 0x01ffc9a7; /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address. bytes32 constant internal ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked("ERC1820_ACCEPT_MAGIC")); /// @notice mapping from addresses and interface hashes to their implementers. mapping(address => mapping(bytes32 => address)) internal interfaces; /// @notice mapping from addresses to their manager. mapping(address => address) internal managers; /// @notice flag for each address and erc165 interface to indicate if it is cached. mapping(address => mapping(bytes4 => bool)) internal erc165Cached; /// @notice Indicates a contract is the 'implementer' of 'interfaceHash' for 'addr'. event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer); /// @notice Indicates 'newManager' is the address of the new manager for 'addr'. event ManagerChanged(address indexed addr, address indexed newManager); /// @notice Query if an address implements an interface and through which contract. /// @param _addr Address being queried for the implementer of an interface. /// (If '_addr' is the zero address then 'msg.sender' is assumed.) /// @param _interfaceHash Keccak256 hash of the name of the interface as a string. /// E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface. /// @return The address of the contract which implements the interface '_interfaceHash' for '_addr' /// or '0' if '_addr' did not register an implementer for this interface. function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) { address addr = _addr == address(0) ? msg.sender : _addr; if (isERC165Interface(_interfaceHash)) { bytes4 erc165InterfaceHash = bytes4(_interfaceHash); return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : address(0); } return interfaces[addr][_interfaceHash]; } /// @notice Sets the contract which implements a specific interface for an address. /// Only the manager defined for that address can set it. /// (Each address is the manager for itself until it sets a new manager.) /// @param _addr Address for which to set the interface. /// (If '_addr' is the zero address then 'msg.sender' is assumed.) /// @param _interfaceHash Keccak256 hash of the name of the interface as a string. /// E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface. /// @param _implementer Contract address implementing '_interfaceHash' for '_addr'. function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external { address addr = _addr == address(0) ? msg.sender : _addr; require(getManager(addr) == msg.sender, "Not the manager"); require(!isERC165Interface(_interfaceHash), "Must not be an ERC165 hash"); if (_implementer != address(0) && _implementer != msg.sender) { require( ERC1820ImplementerInterface(_implementer) .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC1820_ACCEPT_MAGIC, "Does not implement the interface" ); } interfaces[addr][_interfaceHash] = _implementer; emit InterfaceImplementerSet(addr, _interfaceHash, _implementer); } /// @notice Sets '_newManager' as manager for '_addr'. /// The new manager will be able to call 'setInterfaceImplementer' for '_addr'. /// @param _addr Address for which to set the new manager. /// @param _newManager Address of the new manager for 'addr'. (Pass '0x0' to reset the manager to '_addr'.) function setManager(address _addr, address _newManager) external { require(getManager(_addr) == msg.sender, "Not the manager"); managers[_addr] = _newManager == _addr ? address(0) : _newManager; emit ManagerChanged(_addr, _newManager); } /// @notice Get the manager of an address. /// @param _addr Address for which to return the manager. /// @return Address of the manager for a given address. function getManager(address _addr) public view returns(address) { // By default the manager of an address is the same address if (managers[_addr] == address(0)) { return _addr; } else { return managers[_addr]; } } /// @notice Compute the keccak256 hash of an interface given its name. /// @param _interfaceName Name of the interface. /// @return The keccak256 hash of an interface name. function interfaceHash(string calldata _interfaceName) external pure returns(bytes32) { return keccak256(abi.encodePacked(_interfaceName)); } /* --- ERC165 Related Functions --- */ /* --- Developed in collaboration with William Entriken. --- */ /// @notice Updates the cache with whether the contract implements an ERC165 interface or not. /// @param _contract Address of the contract for which to update the cache. /// @param _interfaceId ERC165 interface for which to update the cache. function updateERC165Cache(address _contract, bytes4 _interfaceId) external { interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache( _contract, _interfaceId) ? _contract : address(0); erc165Cached[_contract][_interfaceId] = true; } /// @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 _contract Address of the contract to check. /// @param _interfaceId ERC165 interface to check. /// @return True if '_contract' implements '_interfaceId', false otherwise. function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) { if (!erc165Cached[_contract][_interfaceId]) { return implementsERC165InterfaceNoCache(_contract, _interfaceId); } return interfaces[_contract][_interfaceId] == _contract; } /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache. /// @param _contract Address of the contract to check. /// @param _interfaceId ERC165 interface to check. /// @return True if '_contract' implements '_interfaceId', false otherwise. function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) { uint256 success; uint256 result; (success, result) = noThrowCall(_contract, ERC165ID); if (success == 0 || result == 0) { return false; } (success, result) = noThrowCall(_contract, INVALID_ID); if (success == 0 || result != 0) { return false; } (success, result) = noThrowCall(_contract, _interfaceId); if (success == 1 && result == 1) { return true; } return false; } /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not. /// @param _interfaceHash The hash to check. /// @return True if '_interfaceHash' is an ERC165 interface (ending with 28 zeroes), false otherwise. function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) { return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0; } /// @dev Make a call on a contract without throwing if the function does not exist. function noThrowCall(address _contract, bytes4 _interfaceId) internal view returns (uint256 success, uint256 result) { bytes4 erc165ID = ERC165ID; assembly { let x := mload(0x40) // Find empty storage location using "free memory pointer" mstore(x, erc165ID) // Place signature at beginning of empty storage mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature success := staticcall( 30000, // 30k gas _contract, // To addr x, // Inputs are stored at location x 0x24, // Inputs are 36 (4 + 32) bytes long x, // Store output over input (saves space) 0x20 // Outputs are 32 bytes long ) result := mload(x) // Load the result } } }
File 3 of 8: AdminUpgradeabilityProxy
// File: ownership/Ownable.sol pragma solidity ^0.5.0; /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". * * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/ownership/Ownable.sol * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the * build/artifacts folder) as well as the vanilla Ownable implementation from an openzeppelin version. */ contract OpenZeppelinUpgradesOwnable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor () internal { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } /** * @return the address of the owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner()); _; } /** * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Allows the current owner to relinquish control of the contract. * @notice Renouncing to ownership will leave the contract without an owner. * It will not be possible to call the functions with the `onlyOwner` * modifier anymore. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File: upgradeability/Proxy.sol pragma solidity ^0.5.0; /** * @title Proxy * @dev Implements delegation of calls to other contracts, with proper * forwarding of return values and bubbling of failures. * It defines a fallback function that delegates all calls to the address * returned by the abstract _implementation() internal function. */ contract Proxy { /** * @dev Fallback function. * Implemented entirely in `_fallback`. */ function () payable external { _fallback(); } /** * @return The Address of the implementation. */ function _implementation() internal view returns (address); /** * @dev Delegates execution to an implementation contract. * This is a low level function that doesn't return to its internal call site. * It will return to the external caller whatever the implementation returns. * @param implementation Address to delegate. */ function _delegate(address implementation) internal { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } /** * @dev Function that is run as the first thing in the fallback function. * Can be redefined in derived contracts to add functionality. * Redefinitions must call super._willFallback(). */ function _willFallback() internal { } /** * @dev fallback implementation. * Extracted to enable manual triggering. */ function _fallback() internal { _willFallback(); _delegate(_implementation()); } } // File: utils/Address.sol pragma solidity ^0.5.0; /** * Utility library of inline functions on addresses * * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/utils/Address.sol * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the * build/artifacts folder) as well as the vanilla Address implementation from an openzeppelin version. */ library OpenZeppelinUpgradesAddress { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param account address of the account to check * @return whether the target address is a contract */ function isContract(address account) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } // File: upgradeability/BaseUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title BaseUpgradeabilityProxy * @dev This contract implements a proxy that allows to change the * implementation address to which it will delegate. * Such a change is called an implementation upgrade. */ contract BaseUpgradeabilityProxy is Proxy { /** * @dev Emitted when the implementation is upgraded. * @param implementation Address of the new implementation. */ event Upgraded(address indexed implementation); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation. * @return Address of the current implementation */ function _implementation() internal view returns (address impl) { bytes32 slot = IMPLEMENTATION_SLOT; assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * @param newImplementation Address of the new implementation. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation address of the proxy. * @param newImplementation Address of the new implementation. */ function _setImplementation(address newImplementation) internal { require(OpenZeppelinUpgradesAddress.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, newImplementation) } } } // File: upgradeability/UpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title UpgradeabilityProxy * @dev Extends BaseUpgradeabilityProxy with a constructor for initializing * implementation and init data. */ contract UpgradeabilityProxy is BaseUpgradeabilityProxy { /** * @dev Contract constructor. * @param _logic Address of the initial implementation. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, bytes memory _data) public payable { assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)); _setImplementation(_logic); if(_data.length > 0) { (bool success,) = _logic.delegatecall(_data); require(success); } } } // File: upgradeability/BaseAdminUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title BaseAdminUpgradeabilityProxy * @dev This contract combines an upgradeability proxy with an authorization * mechanism for administrative tasks. * All external functions in this contract must be guarded by the * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity * feature proposal that would enable this to be done automatically. */ contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy { /** * @dev Emitted when the administration has been transferred. * @param previousAdmin Address of the previous admin. * @param newAdmin Address of the new admin. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Modifier to check whether the `msg.sender` is the admin. * If it is, it will run the function. Otherwise, it will delegate the call * to the implementation. */ modifier ifAdmin() { if (msg.sender == _admin()) { _; } else { _fallback(); } } /** * @return The address of the proxy admin. */ function admin() external ifAdmin returns (address) { return _admin(); } /** * @return The address of the implementation. */ function implementation() external ifAdmin returns (address) { return _implementation(); } /** * @dev Changes the admin of the proxy. * Only the current admin can call this function. * @param newAdmin Address to transfer proxy administration to. */ function changeAdmin(address newAdmin) external ifAdmin { require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address"); emit AdminChanged(_admin(), newAdmin); _setAdmin(newAdmin); } /** * @dev Upgrade the backing implementation of the proxy. * Only the admin can call this function. * @param newImplementation Address of the new implementation. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeTo(newImplementation); } /** * @dev Upgrade the backing implementation of the proxy and call a function * on the new implementation. * This is useful to initialize the proxied contract. * @param newImplementation Address of the new implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin { _upgradeTo(newImplementation); (bool success,) = newImplementation.delegatecall(data); require(success); } /** * @return The admin slot. */ function _admin() internal view returns (address adm) { bytes32 slot = ADMIN_SLOT; assembly { adm := sload(slot) } } /** * @dev Sets the address of the proxy admin. * @param newAdmin Address of the new proxy admin. */ function _setAdmin(address newAdmin) internal { bytes32 slot = ADMIN_SLOT; assembly { sstore(slot, newAdmin) } } /** * @dev Only fall back when the sender is not the admin. */ function _willFallback() internal { require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin"); super._willFallback(); } } // File: upgradeability/AdminUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title AdminUpgradeabilityProxy * @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for * initializing the implementation, admin, and init data. */ contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy { /** * Contract constructor. * @param _logic address of the initial implementation. * @param _admin Address of the proxy administrator. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable { assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)); _setAdmin(_admin); } } // File: upgradeability/ProxyAdmin.sol pragma solidity ^0.5.0; /** * @title ProxyAdmin * @dev This contract is the admin of a proxy, and is in charge * of upgrading it as well as transferring it to another admin. */ contract ProxyAdmin is OpenZeppelinUpgradesOwnable { /** * @dev Returns the current implementation of a proxy. * This is needed because only the proxy admin can query it. * @return The address of the current implementation of the proxy. */ function getProxyImplementation(AdminUpgradeabilityProxy proxy) public view returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("implementation()")) == 0x5c60da1b (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); require(success); return abi.decode(returndata, (address)); } /** * @dev Returns the admin of a proxy. Only the admin can query it. * @return The address of the current admin of the proxy. */ function getProxyAdmin(AdminUpgradeabilityProxy proxy) public view returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("admin()")) == 0xf851a440 (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); require(success); return abi.decode(returndata, (address)); } /** * @dev Changes the admin of a proxy. * @param proxy Proxy to change admin. * @param newAdmin Address to transfer proxy administration to. */ function changeProxyAdmin(AdminUpgradeabilityProxy proxy, address newAdmin) public onlyOwner { proxy.changeAdmin(newAdmin); } /** * @dev Upgrades a proxy to the newest implementation of a contract. * @param proxy Proxy to be upgraded. * @param implementation the address of the Implementation. */ function upgrade(AdminUpgradeabilityProxy proxy, address implementation) public onlyOwner { proxy.upgradeTo(implementation); } /** * @dev Upgrades a proxy to the newest implementation of a contract and forwards a function call to it. * This is useful to initialize the proxied contract. * @param proxy Proxy to be upgraded. * @param implementation Address of the Implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeAndCall(AdminUpgradeabilityProxy proxy, address implementation, bytes memory data) payable public onlyOwner { proxy.upgradeToAndCall.value(msg.value)(implementation, data); } }
File 4 of 8: ContractManager
// SPDX-License-Identifier: AGPL-3.0-only /* ContractManager.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.8.17; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; import "./utils/StringUtils.sol"; import "./thirdparty/openzeppelin/InitializableWithGap.sol"; /** * @title ContractManager * @dev Contract contains the actual current mapping from contract IDs * (in the form of human-readable strings) to addresses. */ contract ContractManager is InitializableWithGap, OwnableUpgradeable, IContractManager { using StringUtils for string; using AddressUpgradeable for address; string public constant BOUNTY = "Bounty"; string public constant CONSTANTS_HOLDER = "ConstantsHolder"; string public constant DELEGATION_PERIOD_MANAGER = "DelegationPeriodManager"; string public constant PUNISHER = "Punisher"; string public constant SKALE_TOKEN = "SkaleToken"; string public constant TIME_HELPERS = "TimeHelpers"; string public constant TOKEN_STATE = "TokenState"; string public constant VALIDATOR_SERVICE = "ValidatorService"; // mapping of actual smart contracts addresses mapping (bytes32 => address) public override contracts; function initialize() external override initializer { OwnableUpgradeable.__Ownable_init(); } /** * @dev Allows the Owner to add contract to mapping of contract addresses. * * Emits a {ContractUpgraded} event. * * Requirements: * * - New address is non-zero. * - Contract is not already added. * - Contract address contains code. */ function setContractsAddress( string calldata contractsName, address newContractsAddress ) external override onlyOwner { // check newContractsAddress is not equal to zero require(newContractsAddress != address(0), "New address is equal zero"); // create hash of contractsName bytes32 contractId = keccak256(abi.encodePacked(contractsName)); // check newContractsAddress is not equal the previous contract's address require(contracts[contractId] != newContractsAddress, "Contract is already added"); require(newContractsAddress.isContract(), "Given contract address does not contain code"); // add newContractsAddress to mapping of actual contract addresses contracts[contractId] = newContractsAddress; emit ContractUpgraded(contractsName, newContractsAddress); } /** * @dev Returns contract address. * * Requirements: * * - Contract must exist. */ function getDelegationPeriodManager() external view override returns (address) { return getContract(DELEGATION_PERIOD_MANAGER); } function getBounty() external view override returns (address) { return getContract(BOUNTY); } function getValidatorService() external view override returns (address) { return getContract(VALIDATOR_SERVICE); } function getTimeHelpers() external view override returns (address) { return getContract(TIME_HELPERS); } function getConstantsHolder() external view override returns (address) { return getContract(CONSTANTS_HOLDER); } function getSkaleToken() external view override returns (address) { return getContract(SKALE_TOKEN); } function getTokenState() external view override returns (address) { return getContract(TOKEN_STATE); } function getPunisher() external view override returns (address) { return getContract(PUNISHER); } function getContract(string memory name) public view override returns (address contractAddress) { contractAddress = contracts[keccak256(abi.encodePacked(name))]; if (contractAddress == address(0)) { revert(name.strConcat(" contract has not been found")); } } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // SPDX-License-Identifier: AGPL-3.0-only /* IContractManager.sol - SKALE Manager Interfaces Copyright (C) 2021-Present SKALE Labs @author Dmytro Stebaeiv SKALE Manager Interfaces 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 Interfaces 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 Interfaces. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IContractManager { /** * @dev Emitted when contract is upgraded. */ event ContractUpgraded(string contractsName, address contractsAddress); function initialize() external; function setContractsAddress(string calldata contractsName, address newContractsAddress) external; function contracts(bytes32 nameHash) external view returns (address); function getDelegationPeriodManager() external view returns (address); function getBounty() external view returns (address); function getValidatorService() external view returns (address); function getTimeHelpers() external view returns (address); function getConstantsHolder() external view returns (address); function getSkaleToken() external view returns (address); function getTokenState() external view returns (address); function getPunisher() external view returns (address); function getContract(string calldata name) external view returns (address); }// SPDX-License-Identifier: AGPL-3.0-only /* StringUtils.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Vadim Yavorsky SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.8.17; library StringUtils { function strConcat(string memory a, string memory b) internal pure returns (string memory) { bytes memory _ba = bytes(a); bytes memory _bb = bytes(b); string memory ab = new string(_ba.length + _bb.length); bytes memory strBytes = bytes(ab); uint k = 0; uint i = 0; for (i = 0; i < _ba.length; i++) { strBytes[k++] = _ba[i]; } for (i = 0; i < _bb.length; i++) { strBytes[k++] = _bb[i]; } return string(strBytes); } }// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.7; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract InitializableWithGap is Initializable { uint256[50] private ______gap; } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with 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. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original * initialization step. This is essential to configure modules that are added through upgrades and that require * initialization. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } }
File 5 of 8: AdminUpgradeabilityProxy
// File: ownership/Ownable.sol pragma solidity ^0.5.0; /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". * * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/ownership/Ownable.sol * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the * build/artifacts folder) as well as the vanilla Ownable implementation from an openzeppelin version. */ contract OpenZeppelinUpgradesOwnable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor () internal { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } /** * @return the address of the owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner()); _; } /** * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Allows the current owner to relinquish control of the contract. * @notice Renouncing to ownership will leave the contract without an owner. * It will not be possible to call the functions with the `onlyOwner` * modifier anymore. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File: upgradeability/Proxy.sol pragma solidity ^0.5.0; /** * @title Proxy * @dev Implements delegation of calls to other contracts, with proper * forwarding of return values and bubbling of failures. * It defines a fallback function that delegates all calls to the address * returned by the abstract _implementation() internal function. */ contract Proxy { /** * @dev Fallback function. * Implemented entirely in `_fallback`. */ function () payable external { _fallback(); } /** * @return The Address of the implementation. */ function _implementation() internal view returns (address); /** * @dev Delegates execution to an implementation contract. * This is a low level function that doesn't return to its internal call site. * It will return to the external caller whatever the implementation returns. * @param implementation Address to delegate. */ function _delegate(address implementation) internal { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } /** * @dev Function that is run as the first thing in the fallback function. * Can be redefined in derived contracts to add functionality. * Redefinitions must call super._willFallback(). */ function _willFallback() internal { } /** * @dev fallback implementation. * Extracted to enable manual triggering. */ function _fallback() internal { _willFallback(); _delegate(_implementation()); } } // File: utils/Address.sol pragma solidity ^0.5.0; /** * Utility library of inline functions on addresses * * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/utils/Address.sol * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the * build/artifacts folder) as well as the vanilla Address implementation from an openzeppelin version. */ library OpenZeppelinUpgradesAddress { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param account address of the account to check * @return whether the target address is a contract */ function isContract(address account) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } // File: upgradeability/BaseUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title BaseUpgradeabilityProxy * @dev This contract implements a proxy that allows to change the * implementation address to which it will delegate. * Such a change is called an implementation upgrade. */ contract BaseUpgradeabilityProxy is Proxy { /** * @dev Emitted when the implementation is upgraded. * @param implementation Address of the new implementation. */ event Upgraded(address indexed implementation); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation. * @return Address of the current implementation */ function _implementation() internal view returns (address impl) { bytes32 slot = IMPLEMENTATION_SLOT; assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * @param newImplementation Address of the new implementation. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation address of the proxy. * @param newImplementation Address of the new implementation. */ function _setImplementation(address newImplementation) internal { require(OpenZeppelinUpgradesAddress.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, newImplementation) } } } // File: upgradeability/UpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title UpgradeabilityProxy * @dev Extends BaseUpgradeabilityProxy with a constructor for initializing * implementation and init data. */ contract UpgradeabilityProxy is BaseUpgradeabilityProxy { /** * @dev Contract constructor. * @param _logic Address of the initial implementation. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, bytes memory _data) public payable { assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)); _setImplementation(_logic); if(_data.length > 0) { (bool success,) = _logic.delegatecall(_data); require(success); } } } // File: upgradeability/BaseAdminUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title BaseAdminUpgradeabilityProxy * @dev This contract combines an upgradeability proxy with an authorization * mechanism for administrative tasks. * All external functions in this contract must be guarded by the * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity * feature proposal that would enable this to be done automatically. */ contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy { /** * @dev Emitted when the administration has been transferred. * @param previousAdmin Address of the previous admin. * @param newAdmin Address of the new admin. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Modifier to check whether the `msg.sender` is the admin. * If it is, it will run the function. Otherwise, it will delegate the call * to the implementation. */ modifier ifAdmin() { if (msg.sender == _admin()) { _; } else { _fallback(); } } /** * @return The address of the proxy admin. */ function admin() external ifAdmin returns (address) { return _admin(); } /** * @return The address of the implementation. */ function implementation() external ifAdmin returns (address) { return _implementation(); } /** * @dev Changes the admin of the proxy. * Only the current admin can call this function. * @param newAdmin Address to transfer proxy administration to. */ function changeAdmin(address newAdmin) external ifAdmin { require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address"); emit AdminChanged(_admin(), newAdmin); _setAdmin(newAdmin); } /** * @dev Upgrade the backing implementation of the proxy. * Only the admin can call this function. * @param newImplementation Address of the new implementation. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeTo(newImplementation); } /** * @dev Upgrade the backing implementation of the proxy and call a function * on the new implementation. * This is useful to initialize the proxied contract. * @param newImplementation Address of the new implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin { _upgradeTo(newImplementation); (bool success,) = newImplementation.delegatecall(data); require(success); } /** * @return The admin slot. */ function _admin() internal view returns (address adm) { bytes32 slot = ADMIN_SLOT; assembly { adm := sload(slot) } } /** * @dev Sets the address of the proxy admin. * @param newAdmin Address of the new proxy admin. */ function _setAdmin(address newAdmin) internal { bytes32 slot = ADMIN_SLOT; assembly { sstore(slot, newAdmin) } } /** * @dev Only fall back when the sender is not the admin. */ function _willFallback() internal { require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin"); super._willFallback(); } } // File: upgradeability/AdminUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title AdminUpgradeabilityProxy * @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for * initializing the implementation, admin, and init data. */ contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy { /** * Contract constructor. * @param _logic address of the initial implementation. * @param _admin Address of the proxy administrator. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable { assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)); _setAdmin(_admin); } } // File: upgradeability/ProxyAdmin.sol pragma solidity ^0.5.0; /** * @title ProxyAdmin * @dev This contract is the admin of a proxy, and is in charge * of upgrading it as well as transferring it to another admin. */ contract ProxyAdmin is OpenZeppelinUpgradesOwnable { /** * @dev Returns the current implementation of a proxy. * This is needed because only the proxy admin can query it. * @return The address of the current implementation of the proxy. */ function getProxyImplementation(AdminUpgradeabilityProxy proxy) public view returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("implementation()")) == 0x5c60da1b (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); require(success); return abi.decode(returndata, (address)); } /** * @dev Returns the admin of a proxy. Only the admin can query it. * @return The address of the current admin of the proxy. */ function getProxyAdmin(AdminUpgradeabilityProxy proxy) public view returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("admin()")) == 0xf851a440 (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); require(success); return abi.decode(returndata, (address)); } /** * @dev Changes the admin of a proxy. * @param proxy Proxy to change admin. * @param newAdmin Address to transfer proxy administration to. */ function changeProxyAdmin(AdminUpgradeabilityProxy proxy, address newAdmin) public onlyOwner { proxy.changeAdmin(newAdmin); } /** * @dev Upgrades a proxy to the newest implementation of a contract. * @param proxy Proxy to be upgraded. * @param implementation the address of the Implementation. */ function upgrade(AdminUpgradeabilityProxy proxy, address implementation) public onlyOwner { proxy.upgradeTo(implementation); } /** * @dev Upgrades a proxy to the newest implementation of a contract and forwards a function call to it. * This is useful to initialize the proxied contract. * @param proxy Proxy to be upgraded. * @param implementation Address of the Implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeAndCall(AdminUpgradeabilityProxy proxy, address implementation, bytes memory data) payable public onlyOwner { proxy.upgradeToAndCall.value(msg.value)(implementation, data); } }
File 6 of 8: TokenState
// SPDX-License-Identifier: AGPL-3.0-only /* TokenState.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.8.17; import "@skalenetwork/skale-manager-interfaces/delegation/ITokenState.sol"; import "@skalenetwork/skale-manager-interfaces/delegation/ILocker.sol"; import "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; import "../Permissions.sol"; /** * @title Token State * @dev This contract manages lockers to control token transferability. * * The SKALE Network has three types of locked tokens: * * - Tokens that are transferrable but are currently locked into delegation with * a validator. * * - Tokens that are not transferable from one address to another, but may be * delegated to a validator `getAndUpdateLockedAmount`. This lock enforces * Proof-of-Use requirements. * * - Tokens that are neither transferable nor delegatable * `getAndUpdateForbiddenForDelegationAmount`. This lock enforces slashing. */ contract TokenState is Permissions, ILocker, ITokenState { string[] private _lockers; IDelegationController private _delegationController; bytes32 public constant LOCKER_MANAGER_ROLE = keccak256("LOCKER_MANAGER_ROLE"); modifier onlyLockerManager() { require(hasRole(LOCKER_MANAGER_ROLE, msg.sender), "LOCKER_MANAGER_ROLE is required"); _; } /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ function getAndUpdateLockedAmount(address holder) external override returns (uint) { if (address(_delegationController) == address(0)) { _delegationController = IDelegationController(contractManager.getContract("DelegationController")); } uint locked = 0; if (_delegationController.getDelegationsByHolderLength(holder) > 0) { // the holder ever delegated for (uint i = 0; i < _lockers.length; ++i) { ILocker locker = ILocker(contractManager.getContract(_lockers[i])); locked = locked + locker.getAndUpdateLockedAmount(holder); } } return locked; } /** * @dev See {ILocker-getAndUpdateForbiddenForDelegationAmount}. */ function getAndUpdateForbiddenForDelegationAmount(address holder) external override returns (uint amount) { uint forbidden = 0; for (uint i = 0; i < _lockers.length; ++i) { ILocker locker = ILocker(contractManager.getContract(_lockers[i])); forbidden = forbidden + locker.getAndUpdateForbiddenForDelegationAmount(holder); } return forbidden; } /** * @dev Allows the Owner to remove a contract from the locker. * * Emits a {LockerWasRemoved} event. */ function removeLocker(string calldata locker) external override onlyLockerManager { 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 - 1) { _lockers[index] = _lockers[_lockers.length - 1]; } delete _lockers[_lockers.length - 1]; _lockers.pop(); emit LockerWasRemoved(locker); } } function initialize(address contractManagerAddress) public override initializer { Permissions.initialize(contractManagerAddress); _setupRole(LOCKER_MANAGER_ROLE, msg.sender); addLocker("DelegationController"); addLocker("Punisher"); } /** * @dev Allows the Owner to add a contract to the Locker. * * Emits a {LockerWasAdded} event. */ function addLocker(string memory locker) public override onlyLockerManager { _lockers.push(locker); emit LockerWasAdded(locker); } } // SPDX-License-Identifier: AGPL-3.0-only /* ITokenState.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface ITokenState { /** * @dev Emitted when a contract is added to the locker. */ event LockerWasAdded( string locker ); /** * @dev Emitted when a contract is removed from the locker. */ event LockerWasRemoved( string locker ); function removeLocker(string calldata locker) external; function addLocker(string memory locker) external; } // SPDX-License-Identifier: AGPL-3.0-only /* ILocker.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; /** * @dev Interface of the Locker functions. */ interface ILocker { /** * @dev Returns and updates the total amount of locked tokens of a given * `holder`. */ function getAndUpdateLockedAmount(address wallet) external returns (uint); /** * @dev Returns and updates the total non-transferrable and un-delegatable * amount of a given `holder`. */ function getAndUpdateForbiddenForDelegationAmount(address wallet) external returns (uint); } // SPDX-License-Identifier: AGPL-3.0-only /* IDelegationController.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IDelegationController { enum State { PROPOSED, ACCEPTED, CANCELED, REJECTED, DELEGATED, UNDELEGATION_REQUESTED, COMPLETED } struct Delegation { address holder; // address of token owner uint validatorId; uint amount; uint delegationPeriod; uint created; // time of delegation creation uint started; // month when a delegation becomes active uint finished; // first month after a delegation ends string info; } /** * @dev Emitted when validator was confiscated. */ event Confiscated( uint indexed validatorId, uint amount ); /** * @dev Emitted when validator was confiscated. */ event SlashesProcessed( address indexed holder, uint limit ); /** * @dev Emitted when a delegation is proposed to a validator. */ event DelegationProposed( uint delegationId ); /** * @dev Emitted when a delegation is accepted by a validator. */ event DelegationAccepted( uint delegationId ); /** * @dev Emitted when a delegation is cancelled by the delegator. */ event DelegationRequestCanceledByUser( uint delegationId ); /** * @dev Emitted when a delegation is requested to undelegate. */ event UndelegationRequested( uint delegationId ); function getAndUpdateDelegatedToValidatorNow(uint validatorId) external returns (uint); function getAndUpdateDelegatedAmount(address holder) external returns (uint); function getAndUpdateEffectiveDelegatedByHolderToValidator(address holder, uint validatorId, uint month) external returns (uint effectiveDelegated); function delegate( uint validatorId, uint amount, uint delegationPeriod, string calldata info ) external; function cancelPendingDelegation(uint delegationId) external; function acceptPendingDelegation(uint delegationId) external; function requestUndelegation(uint delegationId) external; function confiscate(uint validatorId, uint amount) external; function getAndUpdateEffectiveDelegatedToValidator(uint validatorId, uint month) external returns (uint); function getAndUpdateDelegatedByHolderToValidatorNow(address holder, uint validatorId) external returns (uint); function processSlashes(address holder, uint limit) external; function processAllSlashes(address holder) external; function getEffectiveDelegatedValuesByValidator(uint validatorId) external view returns (uint[] memory); function getEffectiveDelegatedToValidator(uint validatorId, uint month) external view returns (uint); function getDelegatedToValidator(uint validatorId, uint month) external view returns (uint); function getDelegation(uint delegationId) external view returns (Delegation memory); function getFirstDelegationMonth(address holder, uint validatorId) external view returns(uint); function getDelegationsByValidatorLength(uint validatorId) external view returns (uint); function getDelegationsByHolderLength(address holder) external view returns (uint); function getState(uint delegationId) external view returns (State state); function getLockedInPendingDelegations(address holder) external view returns (uint); function hasUnprocessedSlashes(address holder) external view returns (bool); } // SPDX-License-Identifier: AGPL-3.0-only /* Permissions.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.8.17; import "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; import "@skalenetwork/skale-manager-interfaces/IPermissions.sol"; import "./thirdparty/openzeppelin/AccessControlUpgradeableLegacy.sol"; /** * @title Permissions * @dev Contract is connected module for Upgradeable approach, knows ContractManager */ contract Permissions is AccessControlUpgradeableLegacy, IPermissions { using AddressUpgradeable for address; IContractManager public contractManager; /** * @dev Modifier to make a function callable only when caller is the Owner. * * Requirements: * * - The caller must be the owner. */ modifier onlyOwner() { require(_isOwner(), "Caller is not the owner"); _; } /** * @dev Modifier to make a function callable only when caller is an Admin. * * Requirements: * * - The caller must be an admin. */ modifier onlyAdmin() { require(_isAdmin(msg.sender), "Caller is not an admin"); _; } /** * @dev Modifier to make a function callable only when caller is the Owner * or `contractName` contract. * * Requirements: * * - The caller must be the owner or `contractName`. */ modifier allow(string memory contractName) { require( contractManager.getContract(contractName) == msg.sender || _isOwner(), "Message sender is invalid"); _; } /** * @dev Modifier to make a function callable only when caller is the Owner * or `contractName1` or `contractName2` contract. * * Requirements: * * - The caller must be the owner, `contractName1`, or `contractName2`. */ modifier allowTwo(string memory contractName1, string memory contractName2) { require( contractManager.getContract(contractName1) == msg.sender || contractManager.getContract(contractName2) == msg.sender || _isOwner(), "Message sender is invalid"); _; } /** * @dev Modifier to make a function callable only when caller is the Owner * or `contractName1`, `contractName2`, or `contractName3` contract. * * Requirements: * * - The caller must be the owner, `contractName1`, `contractName2`, or * `contractName3`. */ modifier allowThree(string memory contractName1, string memory contractName2, string memory contractName3) { require( contractManager.getContract(contractName1) == msg.sender || contractManager.getContract(contractName2) == msg.sender || contractManager.getContract(contractName3) == msg.sender || _isOwner(), "Message sender is invalid"); _; } function initialize(address contractManagerAddress) public virtual override initializer { AccessControlUpgradeableLegacy.__AccessControl_init(); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); _setContractManager(contractManagerAddress); } function _isOwner() internal view returns (bool) { return hasRole(DEFAULT_ADMIN_ROLE, msg.sender); } function _isAdmin(address account) internal view returns (bool) { address skaleManagerAddress = contractManager.contracts(keccak256(abi.encodePacked("SkaleManager"))); if (skaleManagerAddress != address(0)) { AccessControlUpgradeableLegacy skaleManager = AccessControlUpgradeableLegacy(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 = IContractManager(contractManagerAddress); } } // SPDX-License-Identifier: AGPL-3.0-only /* IContractManager.sol - SKALE Manager Interfaces Copyright (C) 2021-Present SKALE Labs @author Dmytro Stebaeiv SKALE Manager Interfaces 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 Interfaces 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 Interfaces. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IContractManager { /** * @dev Emitted when contract is upgraded. */ event ContractUpgraded(string contractsName, address contractsAddress); function initialize() external; function setContractsAddress(string calldata contractsName, address newContractsAddress) external; function contracts(bytes32 nameHash) external view returns (address); function getDelegationPeriodManager() external view returns (address); function getBounty() external view returns (address); function getValidatorService() external view returns (address); function getTimeHelpers() external view returns (address); function getConstantsHolder() external view returns (address); function getSkaleToken() external view returns (address); function getTokenState() external view returns (address); function getPunisher() external view returns (address); function getContract(string calldata name) external view returns (address); }// SPDX-License-Identifier: AGPL-3.0-only /* IPermissions.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IPermissions { function initialize(address contractManagerAddress) external; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import "@skalenetwork/skale-manager-interfaces/thirdparty/openzeppelin/IAccessControlUpgradeableLegacy.sol"; import "./InitializableWithGap.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, _msgSender())); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. */ abstract contract AccessControlUpgradeableLegacy is InitializableWithGap, ContextUpgradeable, IAccessControlUpgradeableLegacy { function __AccessControl_init() internal initializer { __Context_init_unchained(); __AccessControl_init_unchained(); } function __AccessControl_init_unchained() internal initializer { } using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; struct RoleData { EnumerableSetUpgradeable.AddressSet members; bytes32 adminRole; } mapping (bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view override returns (bool) { return _roles[role].members.contains(account); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view override returns (uint256) { return _roles[role].members.length(); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view override returns (address) { return _roles[role].members.at(index); } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) public virtual override { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant"); _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) public virtual override { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke"); _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { _roles[role].adminRole = adminRole; } function _grantRole(bytes32 role, address account) private { if (_roles[role].members.add(account)) { emit RoleGranted(role, account, _msgSender()); } } function _revokeRole(bytes32 role, address account) private { if (_roles[role].members.remove(account)) { emit RoleRevoked(role, account, _msgSender()); } } uint256[49] private __gap; } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.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.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. * ==== */ library EnumerableSetUpgradeable { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { 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] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with 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. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; } // SPDX-License-Identifier: AGPL-3.0-only /* IAccessControlUpgradeableLegacy.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IAccessControlUpgradeableLegacy { /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); function grantRole(bytes32 role, address account) external; function revokeRole(bytes32 role, address account) external; function renounceRole(bytes32 role, address account) external; function hasRole(bytes32 role, address account) external view returns (bool); function getRoleMemberCount(bytes32 role) external view returns (uint256); function getRoleMember(bytes32 role, uint256 index) external view returns (address); function getRoleAdmin(bytes32 role) external view returns (bytes32); } // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.7; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract InitializableWithGap is Initializable { uint256[50] private ______gap; } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original * initialization step. This is essential to configure modules that are added through upgrades and that require * initialization. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
File 7 of 8: AdminUpgradeabilityProxy
// File: ownership/Ownable.sol pragma solidity ^0.5.0; /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". * * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/ownership/Ownable.sol * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the * build/artifacts folder) as well as the vanilla Ownable implementation from an openzeppelin version. */ contract OpenZeppelinUpgradesOwnable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor () internal { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } /** * @return the address of the owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner()); _; } /** * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Allows the current owner to relinquish control of the contract. * @notice Renouncing to ownership will leave the contract without an owner. * It will not be possible to call the functions with the `onlyOwner` * modifier anymore. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File: upgradeability/Proxy.sol pragma solidity ^0.5.0; /** * @title Proxy * @dev Implements delegation of calls to other contracts, with proper * forwarding of return values and bubbling of failures. * It defines a fallback function that delegates all calls to the address * returned by the abstract _implementation() internal function. */ contract Proxy { /** * @dev Fallback function. * Implemented entirely in `_fallback`. */ function () payable external { _fallback(); } /** * @return The Address of the implementation. */ function _implementation() internal view returns (address); /** * @dev Delegates execution to an implementation contract. * This is a low level function that doesn't return to its internal call site. * It will return to the external caller whatever the implementation returns. * @param implementation Address to delegate. */ function _delegate(address implementation) internal { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } /** * @dev Function that is run as the first thing in the fallback function. * Can be redefined in derived contracts to add functionality. * Redefinitions must call super._willFallback(). */ function _willFallback() internal { } /** * @dev fallback implementation. * Extracted to enable manual triggering. */ function _fallback() internal { _willFallback(); _delegate(_implementation()); } } // File: utils/Address.sol pragma solidity ^0.5.0; /** * Utility library of inline functions on addresses * * Source https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-solidity/v2.1.3/contracts/utils/Address.sol * This contract is copied here and renamed from the original to avoid clashes in the compiled artifacts * when the user imports a zos-lib contract (that transitively causes this contract to be compiled and added to the * build/artifacts folder) as well as the vanilla Address implementation from an openzeppelin version. */ library OpenZeppelinUpgradesAddress { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param account address of the account to check * @return whether the target address is a contract */ function isContract(address account) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } // File: upgradeability/BaseUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title BaseUpgradeabilityProxy * @dev This contract implements a proxy that allows to change the * implementation address to which it will delegate. * Such a change is called an implementation upgrade. */ contract BaseUpgradeabilityProxy is Proxy { /** * @dev Emitted when the implementation is upgraded. * @param implementation Address of the new implementation. */ event Upgraded(address indexed implementation); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation. * @return Address of the current implementation */ function _implementation() internal view returns (address impl) { bytes32 slot = IMPLEMENTATION_SLOT; assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * @param newImplementation Address of the new implementation. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation address of the proxy. * @param newImplementation Address of the new implementation. */ function _setImplementation(address newImplementation) internal { require(OpenZeppelinUpgradesAddress.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, newImplementation) } } } // File: upgradeability/UpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title UpgradeabilityProxy * @dev Extends BaseUpgradeabilityProxy with a constructor for initializing * implementation and init data. */ contract UpgradeabilityProxy is BaseUpgradeabilityProxy { /** * @dev Contract constructor. * @param _logic Address of the initial implementation. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, bytes memory _data) public payable { assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)); _setImplementation(_logic); if(_data.length > 0) { (bool success,) = _logic.delegatecall(_data); require(success); } } } // File: upgradeability/BaseAdminUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title BaseAdminUpgradeabilityProxy * @dev This contract combines an upgradeability proxy with an authorization * mechanism for administrative tasks. * All external functions in this contract must be guarded by the * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity * feature proposal that would enable this to be done automatically. */ contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy { /** * @dev Emitted when the administration has been transferred. * @param previousAdmin Address of the previous admin. * @param newAdmin Address of the new admin. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Modifier to check whether the `msg.sender` is the admin. * If it is, it will run the function. Otherwise, it will delegate the call * to the implementation. */ modifier ifAdmin() { if (msg.sender == _admin()) { _; } else { _fallback(); } } /** * @return The address of the proxy admin. */ function admin() external ifAdmin returns (address) { return _admin(); } /** * @return The address of the implementation. */ function implementation() external ifAdmin returns (address) { return _implementation(); } /** * @dev Changes the admin of the proxy. * Only the current admin can call this function. * @param newAdmin Address to transfer proxy administration to. */ function changeAdmin(address newAdmin) external ifAdmin { require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address"); emit AdminChanged(_admin(), newAdmin); _setAdmin(newAdmin); } /** * @dev Upgrade the backing implementation of the proxy. * Only the admin can call this function. * @param newImplementation Address of the new implementation. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeTo(newImplementation); } /** * @dev Upgrade the backing implementation of the proxy and call a function * on the new implementation. * This is useful to initialize the proxied contract. * @param newImplementation Address of the new implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin { _upgradeTo(newImplementation); (bool success,) = newImplementation.delegatecall(data); require(success); } /** * @return The admin slot. */ function _admin() internal view returns (address adm) { bytes32 slot = ADMIN_SLOT; assembly { adm := sload(slot) } } /** * @dev Sets the address of the proxy admin. * @param newAdmin Address of the new proxy admin. */ function _setAdmin(address newAdmin) internal { bytes32 slot = ADMIN_SLOT; assembly { sstore(slot, newAdmin) } } /** * @dev Only fall back when the sender is not the admin. */ function _willFallback() internal { require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin"); super._willFallback(); } } // File: upgradeability/AdminUpgradeabilityProxy.sol pragma solidity ^0.5.0; /** * @title AdminUpgradeabilityProxy * @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for * initializing the implementation, admin, and init data. */ contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy { /** * Contract constructor. * @param _logic address of the initial implementation. * @param _admin Address of the proxy administrator. * @param _data Data to send as msg.data to the implementation to initialize the proxied contract. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped. */ constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable { assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)); _setAdmin(_admin); } } // File: upgradeability/ProxyAdmin.sol pragma solidity ^0.5.0; /** * @title ProxyAdmin * @dev This contract is the admin of a proxy, and is in charge * of upgrading it as well as transferring it to another admin. */ contract ProxyAdmin is OpenZeppelinUpgradesOwnable { /** * @dev Returns the current implementation of a proxy. * This is needed because only the proxy admin can query it. * @return The address of the current implementation of the proxy. */ function getProxyImplementation(AdminUpgradeabilityProxy proxy) public view returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("implementation()")) == 0x5c60da1b (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); require(success); return abi.decode(returndata, (address)); } /** * @dev Returns the admin of a proxy. Only the admin can query it. * @return The address of the current admin of the proxy. */ function getProxyAdmin(AdminUpgradeabilityProxy proxy) public view returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("admin()")) == 0xf851a440 (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); require(success); return abi.decode(returndata, (address)); } /** * @dev Changes the admin of a proxy. * @param proxy Proxy to change admin. * @param newAdmin Address to transfer proxy administration to. */ function changeProxyAdmin(AdminUpgradeabilityProxy proxy, address newAdmin) public onlyOwner { proxy.changeAdmin(newAdmin); } /** * @dev Upgrades a proxy to the newest implementation of a contract. * @param proxy Proxy to be upgraded. * @param implementation the address of the Implementation. */ function upgrade(AdminUpgradeabilityProxy proxy, address implementation) public onlyOwner { proxy.upgradeTo(implementation); } /** * @dev Upgrades a proxy to the newest implementation of a contract and forwards a function call to it. * This is useful to initialize the proxied contract. * @param proxy Proxy to be upgraded. * @param implementation Address of the Implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be called, as described in * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeAndCall(AdminUpgradeabilityProxy proxy, address implementation, bytes memory data) payable public onlyOwner { proxy.upgradeToAndCall.value(msg.value)(implementation, data); } }
File 8 of 8: DelegationController
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with 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. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.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. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSetUpgradeable { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { 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] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC777/IERC777.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC777Token standard as defined in the EIP. * * This contract uses the * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let * token holders and recipients react to token movements by using setting implementers * for the associated interfaces in said registry. See {IERC1820Registry} and * {ERC1820Implementer}. */ interface IERC777 { /** * @dev Emitted when `amount` tokens are created by `operator` and assigned to `to`. * * Note that some additional user `data` and `operatorData` can be logged in the event. */ event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); /** * @dev Emitted when `operator` destroys `amount` tokens from `account`. * * Note that some additional user `data` and `operatorData` can be logged in the event. */ event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); /** * @dev Emitted when `operator` is made operator for `tokenHolder`. */ event AuthorizedOperator(address indexed operator, address indexed tokenHolder); /** * @dev Emitted when `operator` is revoked its operator status for `tokenHolder`. */ event RevokedOperator(address indexed operator, address indexed tokenHolder); /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() external view returns (string memory); /** * @dev Returns the smallest part of the token that is not divisible. This * means all token operations (creation, movement and destruction) must have * amounts that are a multiple of this number. * * For most token contracts, this value will equal 1. */ function granularity() external view returns (uint256); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by an account (`owner`). */ function balanceOf(address owner) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * If send or receive hooks are registered for the caller and `recipient`, * the corresponding functions will be called with `data` and empty * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. * * Emits a {Sent} event. * * Requirements * * - the caller must have at least `amount` tokens. * - `recipient` cannot be the zero address. * - if `recipient` is a contract, it must implement the {IERC777Recipient} * interface. */ function send(address recipient, uint256 amount, bytes calldata data) external; /** * @dev Destroys `amount` tokens from the caller's account, reducing the * total supply. * * If a send hook is registered for the caller, the corresponding function * will be called with `data` and empty `operatorData`. See {IERC777Sender}. * * Emits a {Burned} event. * * Requirements * * - the caller must have at least `amount` tokens. */ function burn(uint256 amount, bytes calldata data) external; /** * @dev Returns true if an account is an operator of `tokenHolder`. * Operators can send and burn tokens on behalf of their owners. All * accounts are their own operator. * * See {operatorSend} and {operatorBurn}. */ function isOperatorFor(address operator, address tokenHolder) external view returns (bool); /** * @dev Make an account an operator of the caller. * * See {isOperatorFor}. * * Emits an {AuthorizedOperator} event. * * Requirements * * - `operator` cannot be calling address. */ function authorizeOperator(address operator) external; /** * @dev Revoke an account's operator status for the caller. * * See {isOperatorFor} and {defaultOperators}. * * Emits a {RevokedOperator} event. * * Requirements * * - `operator` cannot be calling address. */ function revokeOperator(address operator) external; /** * @dev Returns the list of default operators. These accounts are operators * for all token holders, even if {authorizeOperator} was never called on * them. * * This list is immutable, but individual holders may revoke these via * {revokeOperator}, in which case {isOperatorFor} will return false. */ function defaultOperators() external view returns (address[] memory); /** * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must * be an operator of `sender`. * * If send or receive hooks are registered for `sender` and `recipient`, * the corresponding functions will be called with `data` and * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. * * Emits a {Sent} event. * * Requirements * * - `sender` cannot be the zero address. * - `sender` must have at least `amount` tokens. * - the caller must be an operator for `sender`. * - `recipient` cannot be the zero address. * - if `recipient` is a contract, it must implement the {IERC777Recipient} * interface. */ function operatorSend( address sender, address recipient, uint256 amount, bytes calldata data, bytes calldata operatorData ) external; /** * @dev Destroys `amount` tokens from `account`, reducing the total supply. * The caller must be an operator of `account`. * * If a send hook is registered for `account`, the corresponding function * will be called with `data` and `operatorData`. See {IERC777Sender}. * * Emits a {Burned} event. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. * - the caller must be an operator for `account`. */ function operatorBurn(address account, uint256 amount, bytes calldata data, bytes calldata operatorData) external; event Sent( address indexed operator, address indexed from, address indexed to, uint256 amount, bytes data, bytes operatorData ); } // SPDX-License-Identifier: AGPL-3.0-only /* IDelegationController.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IDelegationController { enum State { PROPOSED, ACCEPTED, CANCELED, REJECTED, DELEGATED, UNDELEGATION_REQUESTED, COMPLETED } struct Delegation { address holder; // address of token owner uint validatorId; uint amount; uint delegationPeriod; uint created; // time of delegation creation uint started; // month when a delegation becomes active uint finished; // first month after a delegation ends string info; } /** * @dev Emitted when validator was confiscated. */ event Confiscated( uint indexed validatorId, uint amount ); /** * @dev Emitted when validator was confiscated. */ event SlashesProcessed( address indexed holder, uint limit ); /** * @dev Emitted when a delegation is proposed to a validator. */ event DelegationProposed( uint delegationId ); /** * @dev Emitted when a delegation is accepted by a validator. */ event DelegationAccepted( uint delegationId ); /** * @dev Emitted when a delegation is cancelled by the delegator. */ event DelegationRequestCanceledByUser( uint delegationId ); /** * @dev Emitted when a delegation is requested to undelegate. */ event UndelegationRequested( uint delegationId ); function getAndUpdateDelegatedToValidatorNow(uint validatorId) external returns (uint); function getAndUpdateDelegatedAmount(address holder) external returns (uint); function getAndUpdateEffectiveDelegatedByHolderToValidator(address holder, uint validatorId, uint month) external returns (uint effectiveDelegated); function delegate( uint validatorId, uint amount, uint delegationPeriod, string calldata info ) external; function cancelPendingDelegation(uint delegationId) external; function acceptPendingDelegation(uint delegationId) external; function requestUndelegation(uint delegationId) external; function confiscate(uint validatorId, uint amount) external; function getAndUpdateEffectiveDelegatedToValidator(uint validatorId, uint month) external returns (uint); function getAndUpdateDelegatedByHolderToValidatorNow(address holder, uint validatorId) external returns (uint); function processSlashes(address holder, uint limit) external; function processAllSlashes(address holder) external; function getEffectiveDelegatedValuesByValidator(uint validatorId) external view returns (uint[] memory); function getEffectiveDelegatedToValidator(uint validatorId, uint month) external view returns (uint); function getDelegatedToValidator(uint validatorId, uint month) external view returns (uint); function getDelegation(uint delegationId) external view returns (Delegation memory); function getFirstDelegationMonth(address holder, uint validatorId) external view returns(uint); function getDelegationsByValidatorLength(uint validatorId) external view returns (uint); function getDelegationsByHolderLength(address holder) external view returns (uint); function getState(uint delegationId) external view returns (State state); function getLockedInPendingDelegations(address holder) external view returns (uint); function hasUnprocessedSlashes(address holder) external view returns (bool); } // SPDX-License-Identifier: AGPL-3.0-only /* IDelegationPeriodManager.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IDelegationPeriodManager { /** * @dev Emitted when a new delegation period is specified. */ event DelegationPeriodWasSet( uint length, uint stakeMultiplier ); function setDelegationPeriod(uint monthsCount, uint stakeMultiplier) external; function stakeMultipliers(uint monthsCount) external view returns (uint); function isDelegationPeriodAllowed(uint monthsCount) external view returns (bool); } // SPDX-License-Identifier: AGPL-3.0-only /* ILocker.sol - SKALE Manager Copyright (C) 2019-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; /** * @dev Interface of the Locker functions. */ interface ILocker { /** * @dev Returns and updates the total amount of locked tokens of a given * `holder`. */ function getAndUpdateLockedAmount(address wallet) external returns (uint); /** * @dev Returns and updates the total non-transferrable and un-delegatable * amount of a given `holder`. */ function getAndUpdateForbiddenForDelegationAmount(address wallet) external returns (uint); } // SPDX-License-Identifier: AGPL-3.0-only /* IPunisher.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IPunisher { /** * @dev Emitted upon slashing condition. */ event Slash( uint validatorId, uint amount ); /** * @dev Emitted upon forgive condition. */ event Forgive( address wallet, uint amount ); function slash(uint validatorId, uint amount) external; function forgive(address holder, uint amount) external; function handleSlash(address holder, uint amount) external; } // SPDX-License-Identifier: AGPL-3.0-only /* ITimeHelpers.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface ITimeHelpers { function calculateProofOfUseLockEndTime(uint month, uint lockUpPeriodDays) external view returns (uint timestamp); function getCurrentMonth() external view returns (uint); function timestampToYear(uint timestamp) external view returns (uint); function timestampToMonth(uint timestamp) external view returns (uint); function monthToTimestamp(uint month) external view returns (uint timestamp); function addDays(uint fromTimestamp, uint n) external pure returns (uint); function addMonths(uint fromTimestamp, uint n) external pure returns (uint); function addYears(uint fromTimestamp, uint n) external pure returns (uint); } // SPDX-License-Identifier: AGPL-3.0-only /* IValidatorService.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IValidatorService { struct Validator { string name; address validatorAddress; address requestedAddress; string description; uint feeRate; uint registrationTime; uint minimumDelegationAmount; bool acceptNewRequests; } /** * @dev Emitted when a validator registers. */ event ValidatorRegistered( uint validatorId ); /** * @dev Emitted when a validator address changes. */ event ValidatorAddressChanged( uint validatorId, address newAddress ); /** * @dev Emitted when a validator is enabled. */ event ValidatorWasEnabled( uint validatorId ); /** * @dev Emitted when a validator is disabled. */ event ValidatorWasDisabled( uint validatorId ); /** * @dev Emitted when a node address is linked to a validator. */ event NodeAddressWasAdded( uint validatorId, address nodeAddress ); /** * @dev Emitted when a node address is unlinked from a validator. */ event NodeAddressWasRemoved( uint validatorId, address nodeAddress ); /** * @dev Emitted when whitelist disabled. */ event WhitelistDisabled(bool status); /** * @dev Emitted when validator requested new address. */ event RequestNewAddress(uint indexed validatorId, address previousAddress, address newAddress); /** * @dev Emitted when validator set new minimum delegation amount. */ event SetMinimumDelegationAmount(uint indexed validatorId, uint previousMDA, uint newMDA); /** * @dev Emitted when validator set new name. */ event SetValidatorName(uint indexed validatorId, string previousName, string newName); /** * @dev Emitted when validator set new description. */ event SetValidatorDescription(uint indexed validatorId, string previousDescription, string newDescription); /** * @dev Emitted when validator start or stop accepting new delegation requests. */ event AcceptingNewRequests(uint indexed validatorId, bool status); function registerValidator( string calldata name, string calldata description, uint feeRate, uint minimumDelegationAmount ) external returns (uint validatorId); function enableValidator(uint validatorId) external; function disableValidator(uint validatorId) external; function disableWhitelist() external; function requestForNewAddress(address newValidatorAddress) external; function confirmNewAddress(uint validatorId) external; function linkNodeAddress(address nodeAddress, bytes calldata sig) external; function unlinkNodeAddress(address nodeAddress) external; function setValidatorMDA(uint minimumDelegationAmount) external; function setValidatorName(string calldata newName) external; function setValidatorDescription(string calldata newDescription) external; function startAcceptingNewRequests() external; function stopAcceptingNewRequests() external; function removeNodeAddress(uint validatorId, address nodeAddress) external; function getAndUpdateBondAmount(uint validatorId) external returns (uint); function getMyNodesAddresses() external view returns (address[] memory); function getTrustedValidators() external view returns (uint[] memory); function checkValidatorAddressToId(address validatorAddress, uint validatorId) external view returns (bool); function getValidatorIdByNodeAddress(address nodeAddress) external view returns (uint validatorId); function checkValidatorCanReceiveDelegation(uint validatorId, uint amount) external view; function getNodeAddresses(uint validatorId) external view returns (address[] memory); function validatorExists(uint validatorId) external view returns (bool); function validatorAddressExists(address validatorAddress) external view returns (bool); function checkIfValidatorAddressExists(address validatorAddress) external view; function getValidator(uint validatorId) external view returns (Validator memory); function getValidatorId(address validatorAddress) external view returns (uint); function isAcceptingNewRequests(uint validatorId) external view returns (bool); function isAuthorizedValidator(uint validatorId) external view returns (bool); function getValidatorIdByNodeAddressWithoutRevert(address nodeAddress) external view returns (uint validatorId); } // SPDX-License-Identifier: AGPL-3.0-only /* IBountyV2.sol - SKALE Manager Interfaces Copyright (C) 2021-Present SKALE Labs @author Artem Payvin SKALE Manager Interfaces 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 Interfaces 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 Interfaces. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IBountyV2 { /** * @dev Emitted when bounty reduction is turned on or turned off. */ event BountyReduction(bool status); /** * @dev Emitted when a node creation window was changed. */ event NodeCreationWindowWasChanged( uint oldValue, uint newValue ); function calculateBounty(uint nodeIndex) external returns (uint); function enableBountyReduction() external; function disableBountyReduction() external; function setNodeCreationWindowSeconds(uint window) external; function handleDelegationAdd(uint amount, uint month) external; function handleDelegationRemoving(uint amount, uint month) external; function estimateBounty(uint nodeIndex) external view returns (uint); function getNextRewardTimestamp(uint nodeIndex) external view returns (uint); function getEffectiveDelegatedSum() external view returns (uint[] memory); }// SPDX-License-Identifier: AGPL-3.0-only /* IConstantsHolder.sol - SKALE Manager Interfaces Copyright (C) 2021-Present SKALE Labs @author Artem Payvin SKALE Manager Interfaces 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 Interfaces 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 Interfaces. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IConstantsHolder { /** * @dev Emitted when constants updated. */ event ConstantUpdated( bytes32 indexed constantHash, uint previousValue, uint newValue ); function setPeriods(uint32 newRewardPeriod, uint32 newDeltaPeriod) external; function setCheckTime(uint newCheckTime) external; function setLatency(uint32 newAllowableLatency) external; function setMSR(uint newMSR) external; function setLaunchTimestamp(uint timestamp) external; function setRotationDelay(uint newDelay) external; function setProofOfUseLockUpPeriod(uint periodDays) external; function setProofOfUseDelegationPercentage(uint percentage) external; function setLimitValidatorsPerDelegator(uint newLimit) external; function setSchainCreationTimeStamp(uint timestamp) external; function setMinimalSchainLifetime(uint lifetime) external; function setComplaintTimeLimit(uint timeLimit) external; function setMinNodeBalance(uint newMinNodeBalance) external; function reinitialize() external; function msr() external view returns (uint); function launchTimestamp() external view returns (uint); function rotationDelay() external view returns (uint); function limitValidatorsPerDelegator() external view returns (uint); function schainCreationTimeStamp() external view returns (uint); function minimalSchainLifetime() external view returns (uint); function complaintTimeLimit() external view returns (uint); function minNodeBalance() external view returns (uint); } // SPDX-License-Identifier: AGPL-3.0-only /* IContractManager.sol - SKALE Manager Interfaces Copyright (C) 2021-Present SKALE Labs @author Dmytro Stebaeiv SKALE Manager Interfaces 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 Interfaces 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 Interfaces. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IContractManager { /** * @dev Emitted when contract is upgraded. */ event ContractUpgraded(string contractsName, address contractsAddress); function initialize() external; function setContractsAddress(string calldata contractsName, address newContractsAddress) external; function contracts(bytes32 nameHash) external view returns (address); function getDelegationPeriodManager() external view returns (address); function getBounty() external view returns (address); function getValidatorService() external view returns (address); function getTimeHelpers() external view returns (address); function getConstantsHolder() external view returns (address); function getSkaleToken() external view returns (address); function getTokenState() external view returns (address); function getPunisher() external view returns (address); function getContract(string calldata name) external view returns (address); }// SPDX-License-Identifier: AGPL-3.0-only /* IPermissions.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IPermissions { function initialize(address contractManagerAddress) external; } // SPDX-License-Identifier: AGPL-3.0-only /* IAccessControlUpgradeableLegacy.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity >=0.6.10 <0.9.0; interface IAccessControlUpgradeableLegacy { /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); function grantRole(bytes32 role, address account) external; function revokeRole(bytes32 role, address account) external; function renounceRole(bytes32 role, address account) external; function hasRole(bytes32 role, address account) external view returns (bool); function getRoleMemberCount(bytes32 role) external view returns (uint256); function getRoleMember(bytes32 role, uint256 index) external view returns (address); function getRoleAdmin(bytes32 role) external view returns (bytes32); } // SPDX-License-Identifier: AGPL-3.0-only /* DelegationController.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev @author Vadim Yavorsky SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.8.17; import { IERC777 } from "@openzeppelin/contracts/token/ERC777/IERC777.sol"; import { IDelegationController } from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; import { IDelegationPeriodManager } from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationPeriodManager.sol"; import { IPunisher } from "@skalenetwork/skale-manager-interfaces/delegation/IPunisher.sol"; import { IValidatorService } from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; import { ILocker } from "@skalenetwork/skale-manager-interfaces/delegation/ILocker.sol"; import { ITimeHelpers } from "@skalenetwork/skale-manager-interfaces/delegation/ITimeHelpers.sol"; import { IBountyV2 } from "@skalenetwork/skale-manager-interfaces/IBountyV2.sol"; import { IConstantsHolder } from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; import { Permissions } from "../Permissions.sol"; import { FractionUtils } from "../utils/FractionUtils.sol"; import { MathUtils } from "../utils/MathUtils.sol"; import { PartialDifferences } from "./PartialDifferences.sol"; /** * @title Delegation Controller * @dev This contract performs all delegation functions including delegation * requests, and undelegation, etc. * * Delegators and validators may both perform delegations. Validators who perform * delegations to themselves are effectively self-delegating or self-bonding. * * IMPORTANT: Undelegation may be requested at any time, but undelegation is only * performed at the completion of the current delegation period. * * Delegated tokens may be in one of several states: * * - PROPOSED: token holder proposes tokens to delegate to a validator. * - ACCEPTED: token delegations are accepted by a validator and are locked-by-delegation. * - CANCELED: token holder cancels delegation proposal. Only allowed before the proposal is accepted by the validator. * - REJECTED: token proposal expires at the UTC start of the next month. * - DELEGATED: accepted delegations are delegated at the UTC start of the month. * - UNDELEGATION_REQUESTED: token holder requests delegations to undelegate from the validator. * - COMPLETED: undelegation request is completed at the end of the delegation period. */ contract DelegationController is Permissions, ILocker, IDelegationController { using MathUtils for uint; using PartialDifferences for PartialDifferences.Sequence; using PartialDifferences for PartialDifferences.Value; using FractionUtils for FractionUtils.Fraction; struct SlashingLogEvent { FractionUtils.Fraction reducingCoefficient; uint256 nextMonth; } struct SlashingLog { // month => slashing event mapping (uint256 => SlashingLogEvent) slashes; uint256 firstMonth; uint256 lastMonth; } struct DelegationExtras { uint256 lastSlashingMonthBeforeDelegation; } struct SlashingEvent { FractionUtils.Fraction reducingCoefficient; uint256 validatorId; uint256 month; } struct SlashingSignal { address holder; uint256 penalty; } struct LockedInPending { uint256 amount; uint256 month; } struct FirstDelegationMonth { // month uint256 value; //validatorId => month mapping (uint256 => uint256) byValidator; } struct ValidatorsStatistics { // number of validators uint256 number; //validatorId => amount of delegations mapping (uint256 => uint256) delegated; } uint256 public constant UNDELEGATION_PROHIBITION_WINDOW_SECONDS = 3 * 24 * 60 * 60; /// @dev delegations will never be deleted to index in this array may be used like delegation id Delegation[] public delegations; // validatorId => delegationId[] mapping (uint256 => uint256[]) public delegationsByValidator; // holder => delegationId[] mapping (address => uint256[]) public delegationsByHolder; // delegationId => extras mapping(uint256 => DelegationExtras) private _delegationExtras; // validatorId => sequence mapping (uint256 => PartialDifferences.Value) private _delegatedToValidator; // validatorId => sequence mapping (uint256 => PartialDifferences.Sequence) private _effectiveDelegatedToValidator; // validatorId => slashing log mapping (uint256 => SlashingLog) private _slashesOfValidator; // holder => sequence mapping (address => PartialDifferences.Value) private _delegatedByHolder; // holder => validatorId => sequence mapping (address => mapping (uint256 => PartialDifferences.Value)) private _delegatedByHolderToValidator; // holder => validatorId => sequence mapping (address => mapping (uint256 => PartialDifferences.Sequence)) private _effectiveDelegatedByHolderToValidator; SlashingEvent[] private _slashes; // holder => index in _slashes; mapping (address => uint256) private _firstUnprocessedSlashByHolder; // holder => validatorId => month mapping (address => FirstDelegationMonth) private _firstDelegationMonth; // holder => locked in pending mapping (address => LockedInPending) private _lockedInPendingDelegations; mapping (address => ValidatorsStatistics) private _numberOfValidatorsPerDelegator; /** * @dev Modifier to make a function callable only if delegation exists. */ modifier checkDelegationExists(uint256 delegationId) { require(delegationId < delegations.length, "Delegation does not exist"); _; } function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); } /** * @dev Update and return a validator's delegations. */ function getAndUpdateDelegatedToValidatorNow(uint256 validatorId) external override returns (uint256 amount) { return _getAndUpdateDelegatedToValidator(validatorId, _getCurrentMonth()); } /** * @dev Update and return the amount delegated. */ function getAndUpdateDelegatedAmount(address holder) external override returns (uint256 amount) { return _getAndUpdateDelegatedByHolder(holder); } /** * @dev Update and return the effective amount delegated (minus slash) for * the given month. */ function getAndUpdateEffectiveDelegatedByHolderToValidator(address holder, uint256 validatorId, uint256 month) external override allow("Distributor") returns (uint256 effectiveDelegated) { SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(holder); effectiveDelegated = _effectiveDelegatedByHolderToValidator[holder][validatorId] .getAndUpdateValueInSequence(month); _sendSlashingSignals(slashingSignals); } /** * @dev Allows a token holder to create a delegation proposal of an `amount` * and `delegationPeriod` to a `validatorId`. Delegation must be accepted * by the validator before the UTC start of the month, otherwise the * delegation will be rejected. * * The token holder may add additional information in each proposal. * * Emits a {DelegationProposed} event. * * Requirements: * * - Holder must have sufficient delegatable tokens. * - Delegation must be above the validator's minimum delegation amount. * - Delegation period must be allowed. * - Validator must be authorized if trusted list is enabled. * - Validator must be accepting new delegation requests. */ function delegate( uint256 validatorId, uint256 amount, uint256 delegationPeriod, string calldata info ) external override { require( _getDelegationPeriodManager().isDelegationPeriodAllowed(delegationPeriod), "This delegation period is not allowed"); _getValidatorService().checkValidatorCanReceiveDelegation(validatorId, amount); _checkIfDelegationIsAllowed(msg.sender, validatorId); SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(msg.sender); uint256 delegationId = _addDelegation({ holder: msg.sender, validatorId: validatorId, amount: amount, delegationPeriod: delegationPeriod, info: info }); // check that there is enough money uint256 holderBalance = IERC777(contractManager.getSkaleToken()).balanceOf(msg.sender); uint256 forbiddenForDelegation = ILocker(contractManager.getTokenState()) .getAndUpdateForbiddenForDelegationAmount(msg.sender); require(holderBalance >= forbiddenForDelegation, "Token holder does not have enough tokens to delegate"); emit DelegationProposed(delegationId); _sendSlashingSignals(slashingSignals); } /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ function getAndUpdateLockedAmount(address wallet) external override returns (uint256 amount) { return _getAndUpdateLockedAmount(wallet); } /** * @dev See {ILocker-getAndUpdateForbiddenForDelegationAmount}. */ function getAndUpdateForbiddenForDelegationAmount(address wallet) external override returns (uint256 amount) { return _getAndUpdateLockedAmount(wallet); } /** * @dev Allows token holder to cancel a delegation proposal. * * Emits a {DelegationRequestCanceledByUser} event. * * Requirements: * * - `msg.sender` must be the token holder of the delegation proposal. * - Delegation state must be PROPOSED. */ function cancelPendingDelegation(uint256 delegationId) external override checkDelegationExists(delegationId) { require(msg.sender == delegations[delegationId].holder, "Only token holders can cancel delegation request"); require(getState(delegationId) == State.PROPOSED, "Token holders are only able to cancel PROPOSED delegations"); delegations[delegationId].finished = _getCurrentMonth(); _subtractFromLockedInPendingDelegations(delegations[delegationId].holder, delegations[delegationId].amount); emit DelegationRequestCanceledByUser(delegationId); } /** * @dev Allows a validator to accept a proposed delegation. * Successful acceptance of delegations transition the tokens from a * PROPOSED state to ACCEPTED, and tokens are locked for the remainder of the * delegation period. * * Emits a {DelegationAccepted} event. * * Requirements: * * - Validator must be recipient of proposal. * - Delegation state must be PROPOSED. */ function acceptPendingDelegation(uint256 delegationId) external override checkDelegationExists(delegationId) { require( _getValidatorService().checkValidatorAddressToId(msg.sender, delegations[delegationId].validatorId), "No permissions to accept request"); _accept(delegationId); } /** * @dev Allows delegator to undelegate a specific delegation. * * Emits UndelegationRequested event. * * Requirements: * * - `msg.sender` must be the delegator or the validator. * - Delegation state must be DELEGATED. */ function requestUndelegation(uint256 delegationId) external override checkDelegationExists(delegationId) { require(getState(delegationId) == State.DELEGATED, "Cannot request undelegation"); IValidatorService validatorService = _getValidatorService(); require( delegations[delegationId].holder == msg.sender || (validatorService.validatorAddressExists(msg.sender) && delegations[delegationId].validatorId == validatorService.getValidatorId(msg.sender)), "Permission denied to request undelegation"); _removeValidatorFromValidatorsPerDelegators( delegations[delegationId].holder, delegations[delegationId].validatorId); processAllSlashes(msg.sender); delegations[delegationId].finished = _calculateDelegationEndMonth(delegationId); require( block.timestamp + UNDELEGATION_PROHIBITION_WINDOW_SECONDS < _getTimeHelpers().monthToTimestamp(delegations[delegationId].finished), "Undelegation requests must be sent 3 days before the end of delegation period" ); _subtractFromAllStatistics(delegationId); emit UndelegationRequested(delegationId); } /** * @dev Allows Punisher contract to slash an `amount` of stake from * a validator. This slashes an amount of delegations of the validator, * which reduces the amount that the validator has staked. This consequence * may force the SKALE Manager to reduce the number of nodes a validator is * operating so the validator can meet the Minimum Staking Requirement. * * Emits a {SlashingEvent}. * * See {Punisher}. */ function confiscate(uint256 validatorId, uint256 amount) external override allow("Punisher") { uint256 currentMonth = _getCurrentMonth(); FractionUtils.Fraction memory coefficient = _delegatedToValidator[validatorId].reduceValue(amount, currentMonth); uint256 initialEffectiveDelegated = _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(currentMonth); uint256[] memory initialSubtractions = new uint256[](0); if (currentMonth < _effectiveDelegatedToValidator[validatorId].lastChangedMonth) { initialSubtractions = new uint256[]( _effectiveDelegatedToValidator[validatorId].lastChangedMonth - currentMonth ); for (uint256 i = 0; i < initialSubtractions.length; ++i) { initialSubtractions[i] = _effectiveDelegatedToValidator[validatorId] .subtractDiff[currentMonth + i + 1]; } } _effectiveDelegatedToValidator[validatorId].reduceSequence(coefficient, currentMonth); _putToSlashingLog(_slashesOfValidator[validatorId], coefficient, currentMonth); _slashes.push(SlashingEvent({reducingCoefficient: coefficient, validatorId: validatorId, month: currentMonth})); IBountyV2 bounty = _getBounty(); bounty.handleDelegationRemoving( initialEffectiveDelegated - _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(currentMonth), currentMonth ); for (uint256 i = 0; i < initialSubtractions.length; ++i) { bounty.handleDelegationAdd( initialSubtractions[i] - _effectiveDelegatedToValidator[validatorId].subtractDiff[currentMonth + i + 1], currentMonth + i + 1 ); } emit Confiscated(validatorId, amount); } /** * @dev Allows Distributor contract to return and update the effective * amount delegated (minus slash) to a validator for a given month. */ function getAndUpdateEffectiveDelegatedToValidator(uint256 validatorId, uint256 month) external override allowTwo("Bounty", "Distributor") returns (uint256 amount) { return _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(month); } /** * @dev Return and update the amount delegated to a validator for the * current month. */ function getAndUpdateDelegatedByHolderToValidatorNow(address holder, uint256 validatorId) external override returns (uint256 amount) { return _getAndUpdateDelegatedByHolderToValidator(holder, validatorId, _getCurrentMonth()); } function getEffectiveDelegatedValuesByValidator( uint256 validatorId ) external view override returns (uint256[] memory amounts) { return _effectiveDelegatedToValidator[validatorId].getValuesInSequence(); } function getEffectiveDelegatedToValidator( uint256 validatorId, uint256 month ) external view override returns (uint256 amount) { return _effectiveDelegatedToValidator[validatorId].getValueInSequence(month); } function getDelegatedToValidator( uint256 validatorId, uint256 month ) external view override returns (uint256 amount) { return _delegatedToValidator[validatorId].getValue(month); } /** * @dev Return Delegation struct. */ function getDelegation(uint256 delegationId) external view override checkDelegationExists(delegationId) returns (Delegation memory delegation) { return delegations[delegationId]; } /** * @dev Returns the first delegation month. */ function getFirstDelegationMonth( address holder, uint256 validatorId ) external view override returns(uint256 month) { return _firstDelegationMonth[holder].byValidator[validatorId]; } /** * @dev Returns a validator's total number of delegations. */ function getDelegationsByValidatorLength(uint256 validatorId) external view override returns (uint256 length) { return delegationsByValidator[validatorId].length; } /** * @dev Returns a holder's total number of delegations. */ function getDelegationsByHolderLength(address holder) external view override returns (uint256 length) { return delegationsByHolder[holder].length; } /** * @dev Process slashes up to the given limit. */ function processSlashes(address holder, uint256 limit) public override { _sendSlashingSignals(_processSlashesWithoutSignals(holder, limit)); emit SlashesProcessed(holder, limit); } /** * @dev Process all slashes. */ function processAllSlashes(address holder) public override { processSlashes(holder, 0); } /** * @dev Returns the token state of a given delegation. */ function getState(uint256 delegationId) public view override checkDelegationExists(delegationId) returns (State state) { if (delegations[delegationId].started == 0) { if (delegations[delegationId].finished == 0) { if (_getCurrentMonth() == _getTimeHelpers().timestampToMonth(delegations[delegationId].created)) { return State.PROPOSED; } else { return State.REJECTED; } } else { return State.CANCELED; } } else { if (_getCurrentMonth() < delegations[delegationId].started) { return State.ACCEPTED; } else { if (delegations[delegationId].finished == 0) { return State.DELEGATED; } else { if (_getCurrentMonth() < delegations[delegationId].finished) { return State.UNDELEGATION_REQUESTED; } else { return State.COMPLETED; } } } } } /** * @dev Returns the amount of tokens in PENDING delegation state. */ function getLockedInPendingDelegations(address holder) public view override returns (uint256 amount) { uint256 currentMonth = _getCurrentMonth(); if (_lockedInPendingDelegations[holder].month < currentMonth) { return 0; } else { return _lockedInPendingDelegations[holder].amount; } } /** * @dev Checks whether there are any unprocessed slashes. */ function hasUnprocessedSlashes(address holder) public view override returns (bool hasUnprocessed) { return _everDelegated(holder) && _firstUnprocessedSlashByHolder[holder] < _slashes.length; } // private /** * @dev Allows Nodes contract to get and update the amount delegated * to validator for a given month. */ function _getAndUpdateDelegatedToValidator(uint256 validatorId, uint256 month) private returns (uint256 amount) { return _delegatedToValidator[validatorId].getAndUpdateValue(month); } /** * @dev Adds a new delegation proposal. */ function _addDelegation( address holder, uint256 validatorId, uint256 amount, uint256 delegationPeriod, string memory info ) private returns (uint256 delegationId) { delegationId = delegations.length; delegations.push(Delegation({ holder: holder, validatorId: validatorId, amount: amount, delegationPeriod: delegationPeriod, created: block.timestamp, started: 0, finished: 0, info: info })); delegationsByValidator[validatorId].push(delegationId); delegationsByHolder[holder].push(delegationId); _addToLockedInPendingDelegations(delegations[delegationId].holder, delegations[delegationId].amount); } function _addToDelegatedToValidator(uint256 validatorId, uint256 amount, uint256 month) private { _delegatedToValidator[validatorId].addToValue(amount, month); } function _addToEffectiveDelegatedToValidator(uint256 validatorId, uint256 effectiveAmount, uint256 month) private { _effectiveDelegatedToValidator[validatorId].addToSequence(effectiveAmount, month); } function _addToDelegatedByHolder(address holder, uint256 amount, uint256 month) private { _delegatedByHolder[holder].addToValue(amount, month); } function _addToDelegatedByHolderToValidator( address holder, uint256 validatorId, uint256 amount, uint256 month) private { _delegatedByHolderToValidator[holder][validatorId].addToValue(amount, month); } function _addValidatorToValidatorsPerDelegators(address holder, uint256 validatorId) private { if (_numberOfValidatorsPerDelegator[holder].delegated[validatorId] == 0) { _numberOfValidatorsPerDelegator[holder].number += 1; } _numberOfValidatorsPerDelegator[holder].delegated[validatorId] += 1; } function _removeFromDelegatedByHolder(address holder, uint256 amount, uint256 month) private { _delegatedByHolder[holder].subtractFromValue(amount, month); } function _removeFromDelegatedByHolderToValidator( address holder, uint256 validatorId, uint256 amount, uint256 month) private { _delegatedByHolderToValidator[holder][validatorId].subtractFromValue(amount, month); } function _removeValidatorFromValidatorsPerDelegators(address holder, uint256 validatorId) private { if (_numberOfValidatorsPerDelegator[holder].delegated[validatorId] == 1) { _numberOfValidatorsPerDelegator[holder].number -= 1; } _numberOfValidatorsPerDelegator[holder].delegated[validatorId] -= 1; } function _addToEffectiveDelegatedByHolderToValidator( address holder, uint256 validatorId, uint256 effectiveAmount, uint256 month) private { _effectiveDelegatedByHolderToValidator[holder][validatorId].addToSequence(effectiveAmount, month); } function _removeFromEffectiveDelegatedByHolderToValidator( address holder, uint256 validatorId, uint256 effectiveAmount, uint256 month) private { _effectiveDelegatedByHolderToValidator[holder][validatorId].subtractFromSequence(effectiveAmount, month); } function _getAndUpdateDelegatedByHolder(address holder) private returns (uint256 amount) { uint256 currentMonth = _getCurrentMonth(); processAllSlashes(holder); return _delegatedByHolder[holder].getAndUpdateValue(currentMonth); } function _getAndUpdateDelegatedByHolderToValidator( address holder, uint256 validatorId, uint256 month) private returns (uint256 amount) { return _delegatedByHolderToValidator[holder][validatorId].getAndUpdateValue(month); } function _addToLockedInPendingDelegations(address holder, uint256 amount) private { uint256 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 + amount; } } function _subtractFromLockedInPendingDelegations(address holder, uint256 amount) private { uint256 currentMonth = _getCurrentMonth(); assert(_lockedInPendingDelegations[holder].month == currentMonth); _lockedInPendingDelegations[holder].amount = _lockedInPendingDelegations[holder].amount - amount; } /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ function _getAndUpdateLockedAmount(address wallet) private returns (uint256 amount) { return _getAndUpdateDelegatedByHolder(wallet) + getLockedInPendingDelegations(wallet); } function _updateFirstDelegationMonth(address holder, uint256 validatorId, uint256 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 _removeFromDelegatedToValidator(uint256 validatorId, uint256 amount, uint256 month) private { _delegatedToValidator[validatorId].subtractFromValue(amount, month); } function _removeFromEffectiveDelegatedToValidator( uint256 validatorId, uint256 effectiveAmount, uint256 month ) private { _effectiveDelegatedToValidator[validatorId].subtractFromSequence(effectiveAmount, month); } function _putToSlashingLog( SlashingLog storage log, FractionUtils.Fraction memory coefficient, uint256 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, uint256 limit) private returns (SlashingSignal[] memory slashingSignals) { if (hasUnprocessedSlashes(holder)) { uint256 index = _firstUnprocessedSlashByHolder[holder]; uint256 end = _slashes.length; if (limit > 0 && (index + limit) < end) { end = index + limit; } slashingSignals = new SlashingSignal[](end - index); uint256 begin = index; for (; index < end; ++index) { uint256 validatorId = _slashes[index].validatorId; uint256 month = _slashes[index].month; uint256 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 - begin].holder = holder; slashingSignals[index - begin].penalty = oldValue.boundedSub(_getAndUpdateDelegatedByHolderToValidator(holder, validatorId, month)); } } _firstUnprocessedSlashByHolder[holder] = end; } } function _processAllSlashesWithoutSignals(address holder) private returns (SlashingSignal[] memory slashingSignals) { return _processSlashesWithoutSignals(holder, 0); } function _sendSlashingSignals(SlashingSignal[] memory slashingSignals) private { IPunisher punisher = IPunisher(contractManager.getPunisher()); address previousHolder = address(0); uint256 accumulatedPenalty = 0; for (uint256 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 + slashingSignals[i].penalty; } } if (accumulatedPenalty > 0) { punisher.handleSlash(previousHolder, accumulatedPenalty); } } function _addToAllStatistics(uint256 delegationId) private { uint256 currentMonth = _getCurrentMonth(); delegations[delegationId].started = currentMonth + 1; if (_slashesOfValidator[delegations[delegationId].validatorId].lastMonth > 0) { _delegationExtras[delegationId].lastSlashingMonthBeforeDelegation = _slashesOfValidator[delegations[delegationId].validatorId].lastMonth; } _addToDelegatedToValidator( delegations[delegationId].validatorId, delegations[delegationId].amount, currentMonth + 1); _addToDelegatedByHolder( delegations[delegationId].holder, delegations[delegationId].amount, currentMonth + 1); _addToDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, delegations[delegationId].amount, currentMonth + 1); _updateFirstDelegationMonth( delegations[delegationId].holder, delegations[delegationId].validatorId, currentMonth + 1); uint256 effectiveAmount = delegations[delegationId].amount * _getDelegationPeriodManager().stakeMultipliers(delegations[delegationId].delegationPeriod); _addToEffectiveDelegatedToValidator( delegations[delegationId].validatorId, effectiveAmount, currentMonth + 1); _addToEffectiveDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, effectiveAmount, currentMonth + 1); _addValidatorToValidatorsPerDelegators( delegations[delegationId].holder, delegations[delegationId].validatorId ); } function _subtractFromAllStatistics(uint256 delegationId) private { uint256 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); uint256 effectiveAmount = amountAfterSlashing * _getDelegationPeriodManager().stakeMultipliers(delegations[delegationId].delegationPeriod); _removeFromEffectiveDelegatedToValidator( delegations[delegationId].validatorId, effectiveAmount, delegations[delegationId].finished); _removeFromEffectiveDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, effectiveAmount, delegations[delegationId].finished); _getBounty().handleDelegationRemoving( effectiveAmount, delegations[delegationId].finished); } function _accept(uint256 delegationId) private { _checkIfDelegationIsAllowed(delegations[delegationId].holder, delegations[delegationId].validatorId); State currentState = getState(delegationId); if (currentState != State.PROPOSED) { if (currentState == State.ACCEPTED || currentState == State.DELEGATED || currentState == State.UNDELEGATION_REQUESTED || currentState == State.COMPLETED) { revert("The delegation has been already accepted"); } else if (currentState == State.CANCELED) { revert("The delegation has been cancelled by token holder"); } else if (currentState == State.REJECTED) { revert("The delegation request is outdated"); } } require(currentState == State.PROPOSED, "Cannot set delegation state to accepted"); SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(delegations[delegationId].holder); _addToAllStatistics(delegationId); uint256 amount = delegations[delegationId].amount; uint256 effectiveAmount = amount * _getDelegationPeriodManager().stakeMultipliers(delegations[delegationId].delegationPeriod); _getBounty().handleDelegationAdd( effectiveAmount, delegations[delegationId].started ); _sendSlashingSignals(slashingSignals); emit DelegationAccepted(delegationId); } function _getCurrentMonth() private view returns (uint256 month) { return _getTimeHelpers().getCurrentMonth(); } /** * @dev Checks whether the holder has performed a delegation. */ function _everDelegated(address holder) private view returns (bool delegated) { return _firstDelegationMonth[holder].value > 0; } /** * @dev Returns the month when a delegation ends. */ function _calculateDelegationEndMonth(uint256 delegationId) private view returns (uint256 month) { uint256 currentMonth = _getCurrentMonth(); uint256 started = delegations[delegationId].started; if (currentMonth < started) { return started + delegations[delegationId].delegationPeriod; } else { uint256 completedPeriods = (currentMonth - started) / delegations[delegationId].delegationPeriod; return started + (completedPeriods + 1) * delegations[delegationId].delegationPeriod; } } /** * @dev Returns the delegated amount after a slashing event. */ function _calculateDelegationAmountAfterSlashing(uint256 delegationId) private view returns (uint256 amount) { uint256 startMonth = _delegationExtras[delegationId].lastSlashingMonthBeforeDelegation; uint256 validatorId = delegations[delegationId].validatorId; amount = delegations[delegationId].amount; if (startMonth == 0) { startMonth = _slashesOfValidator[validatorId].firstMonth; if (startMonth == 0) { return amount; } } for (uint256 i = startMonth; i > 0 && i < delegations[delegationId].finished; i = _slashesOfValidator[validatorId].slashes[i].nextMonth) { if (i >= delegations[delegationId].started) { amount = amount * _slashesOfValidator[validatorId].slashes[i].reducingCoefficient.numerator / _slashesOfValidator[validatorId].slashes[i].reducingCoefficient.denominator; } } return amount; } /** * @dev Checks whether delegation to a validator is allowed. * * Requirements: * * - Delegator must not have reached the validator limit. * - Delegation must be made in or after the first delegation month. */ function _checkIfDelegationIsAllowed(address holder, uint256 validatorId) private view { require( _numberOfValidatorsPerDelegator[holder].delegated[validatorId] > 0 || _numberOfValidatorsPerDelegator[holder].number < _getConstantsHolder().limitValidatorsPerDelegator(), "Limit of validators is reached" ); } function _getDelegationPeriodManager() private view returns (IDelegationPeriodManager delegationPeriodManager) { return IDelegationPeriodManager(contractManager.getDelegationPeriodManager()); } function _getBounty() private view returns (IBountyV2 bountyV2) { return IBountyV2(contractManager.getBounty()); } function _getValidatorService() private view returns (IValidatorService validatorService) { return IValidatorService(contractManager.getValidatorService()); } function _getTimeHelpers() private view returns (ITimeHelpers timeHelpers) { return ITimeHelpers(contractManager.getTimeHelpers()); } function _getConstantsHolder() private view returns (IConstantsHolder constantsHolder) { return IConstantsHolder(contractManager.getConstantsHolder()); } } // SPDX-License-Identifier: AGPL-3.0-only /* PartialDifferences.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.8.17; import { MathUtils } from "../utils/MathUtils.sol"; import { FractionUtils } from "../utils/FractionUtils.sol"; /** * @title Partial Differences Library * @dev This library contains functions to manage Partial Differences data * structure. Partial Differences is an array of value differences over time. * * For example: assuming an array [3, 6, 3, 1, 2], partial differences can * represent this array as [_, 3, -3, -2, 1]. * * This data structure allows adding values on an open interval with O(1) * complexity. * * For example: add +5 to [3, 6, 3, 1, 2] starting from the second element (3), * instead of performing [3, 6, 3+5, 1+5, 2+5] partial differences allows * performing [_, 3, -3+5, -2, 1]. The original array can be restored by * adding values from partial differences. */ library PartialDifferences { using MathUtils for uint; struct Sequence { // month => diff mapping (uint256 => uint256) addDiff; // month => diff mapping (uint256 => uint256) subtractDiff; // month => value mapping (uint256 => uint256) value; uint256 firstUnprocessedMonth; uint256 lastChangedMonth; } struct Value { // month => diff mapping (uint256 => uint256) addDiff; // month => diff mapping (uint256 => uint256) subtractDiff; uint256 value; uint256 firstUnprocessedMonth; uint256 lastChangedMonth; } // functions for sequence function addToSequence(Sequence storage sequence, uint256 diff, uint256 month) internal { require(sequence.firstUnprocessedMonth <= month, "Cannot add to the past"); if (sequence.firstUnprocessedMonth == 0) { sequence.firstUnprocessedMonth = month; } sequence.addDiff[month] = sequence.addDiff[month] + diff; if (sequence.lastChangedMonth != month) { sequence.lastChangedMonth = month; } } function subtractFromSequence(Sequence storage sequence, uint256 diff, uint256 month) internal { require(sequence.firstUnprocessedMonth <= month, "Cannot subtract from the past"); if (sequence.firstUnprocessedMonth == 0) { sequence.firstUnprocessedMonth = month; } sequence.subtractDiff[month] = sequence.subtractDiff[month] + diff; if (sequence.lastChangedMonth != month) { sequence.lastChangedMonth = month; } } function getAndUpdateValueInSequence(Sequence storage sequence, uint256 month) internal returns (uint256 value) { if (sequence.firstUnprocessedMonth == 0) { return 0; } if (sequence.firstUnprocessedMonth <= month) { for (uint256 i = sequence.firstUnprocessedMonth; i <= month; ++i) { uint256 nextValue = (sequence.value[i - 1] + 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 + 1; } return sequence.value[month]; } function reduceSequence( Sequence storage sequence, FractionUtils.Fraction memory reducingCoefficient, uint256 month) internal { require(month + 1 >= sequence.firstUnprocessedMonth, "Cannot reduce value in the past"); require( reducingCoefficient.numerator <= reducingCoefficient.denominator, "Increasing of values is not implemented"); if (sequence.firstUnprocessedMonth == 0) { return; } uint256 value = getAndUpdateValueInSequence(sequence, month); if (value.approximatelyEqual(0)) { return; } sequence.value[month] = sequence.value[month] * reducingCoefficient.numerator / reducingCoefficient.denominator; for (uint256 i = month + 1; i <= sequence.lastChangedMonth; ++i) { sequence.subtractDiff[i] = sequence.subtractDiff[i] * reducingCoefficient.numerator / reducingCoefficient.denominator; } } // functions for value function addToValue(Value storage sequence, uint256 diff, uint256 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] + diff; } else { sequence.value = sequence.value + diff; } } function subtractFromValue(Value storage sequence, uint256 diff, uint256 month) internal { require(sequence.firstUnprocessedMonth <= month + 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] + diff; } else { sequence.value = sequence.value.boundedSub(diff); } } function getAndUpdateValue(Value storage sequence, uint256 month) internal returns (uint256 value) { require( month + 1 >= sequence.firstUnprocessedMonth, "Cannot calculate value in the past"); if (sequence.firstUnprocessedMonth == 0) { return 0; } if (sequence.firstUnprocessedMonth <= month) { value = sequence.value; for (uint256 i = sequence.firstUnprocessedMonth; i <= month; ++i) { value = (value + sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]); if (sequence.addDiff[i] > 0) { delete sequence.addDiff[i]; } if (sequence.subtractDiff[i] > 0) { delete sequence.subtractDiff[i]; } } if (sequence.value != value) { sequence.value = value; } sequence.firstUnprocessedMonth = month + 1; } return sequence.value; } function reduceValue( Value storage sequence, uint256 amount, uint256 month) internal returns (FractionUtils.Fraction memory reducingCoefficient) { require(month + 1 >= sequence.firstUnprocessedMonth, "Cannot reduce value in the past"); if (sequence.firstUnprocessedMonth == 0) { return FractionUtils.createFraction(0); } uint256 value = getAndUpdateValue(sequence, month); if (value.approximatelyEqual(0)) { return FractionUtils.createFraction(0); } uint256 _amount = amount; if (value < amount) { _amount = value; } reducingCoefficient = FractionUtils.createFraction(value.boundedSub(_amount), value); reduceValueByCoefficient(sequence, reducingCoefficient, month); return reducingCoefficient; } function reduceValueByCoefficient( Value storage sequence, FractionUtils.Fraction memory reducingCoefficient, uint256 month) internal { reduceValueByCoefficientAndUpdateSumIfNeeded({ sequence: sequence, sumSequence: sequence, reducingCoefficient: reducingCoefficient, month: month, hasSumSequence: false }); } function reduceValueByCoefficientAndUpdateSum( Value storage sequence, Value storage sumSequence, FractionUtils.Fraction memory reducingCoefficient, uint256 month) internal { reduceValueByCoefficientAndUpdateSumIfNeeded({ sequence: sequence, sumSequence: sumSequence, reducingCoefficient: reducingCoefficient, month: month, hasSumSequence: true }); } function reduceValueByCoefficientAndUpdateSumIfNeeded( Value storage sequence, Value storage sumSequence, FractionUtils.Fraction memory reducingCoefficient, uint256 month, bool hasSumSequence) internal { require(month + 1 >= sequence.firstUnprocessedMonth, "Cannot reduce value in the past"); if (hasSumSequence) { require(month + 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; } uint256 value = getAndUpdateValue(sequence, month); if (value.approximatelyEqual(0)) { return; } uint256 newValue = sequence.value * reducingCoefficient.numerator / reducingCoefficient.denominator; if (hasSumSequence) { subtractFromValue(sumSequence, sequence.value.boundedSub(newValue), month); } sequence.value = newValue; for (uint256 i = month + 1; i <= sequence.lastChangedMonth; ++i) { uint256 newDiff = sequence.subtractDiff[i] * reducingCoefficient.numerator / reducingCoefficient.denominator; if (hasSumSequence) { sumSequence.subtractDiff[i] = sumSequence.subtractDiff[i] .boundedSub(sequence.subtractDiff[i].boundedSub(newDiff)); } sequence.subtractDiff[i] = newDiff; } } function getValueInSequence(Sequence storage sequence, uint256 month) internal view returns (uint256 value) { if (sequence.firstUnprocessedMonth == 0) { return 0; } if (sequence.firstUnprocessedMonth <= month) { value = sequence.value[sequence.firstUnprocessedMonth - 1]; for (uint256 i = sequence.firstUnprocessedMonth; i <= month; ++i) { value = value + sequence.addDiff[i] - sequence.subtractDiff[i]; } return value; } else { return sequence.value[month]; } } function getValuesInSequence(Sequence storage sequence) internal view returns (uint256[] memory values) { if (sequence.firstUnprocessedMonth == 0) { return values; } uint256 begin = sequence.firstUnprocessedMonth - 1; uint256 end = sequence.lastChangedMonth + 1; if (end <= begin) { end = begin + 1; } values = new uint256[](end - begin); values[0] = sequence.value[sequence.firstUnprocessedMonth - 1]; for (uint256 i = 0; i + 1 < values.length; ++i) { uint256 month = sequence.firstUnprocessedMonth + i; values[i + 1] = values[i] + sequence.addDiff[month] - sequence.subtractDiff[month]; } } function getValue(Value storage sequence, uint256 month) internal view returns (uint256 value) { require( month + 1 >= sequence.firstUnprocessedMonth, "Cannot calculate value in the past"); if (sequence.firstUnprocessedMonth == 0) { return 0; } if (sequence.firstUnprocessedMonth <= month) { value = sequence.value; for (uint256 i = sequence.firstUnprocessedMonth; i <= month; ++i) { value = value + sequence.addDiff[i] - sequence.subtractDiff[i]; } return value; } else { return sequence.value; } } function getValues(Value storage sequence) internal view returns (uint256[] memory values) { if (sequence.firstUnprocessedMonth == 0) { return values; } uint256 begin = sequence.firstUnprocessedMonth - 1; uint256 end = sequence.lastChangedMonth + 1; if (end <= begin) { end = begin + 1; } values = new uint256[](end - begin); values[0] = sequence.value; for (uint256 i = 0; i + 1 < values.length; ++i) { uint256 month = sequence.firstUnprocessedMonth + i; values[i + 1] = values[i] + sequence.addDiff[month] - sequence.subtractDiff[month]; } } } // SPDX-License-Identifier: AGPL-3.0-only /* Permissions.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.8.17; import { AddressUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import { IContractManager } from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; import { IPermissions } from "@skalenetwork/skale-manager-interfaces/IPermissions.sol"; import { AccessControlUpgradeableLegacy } from "./thirdparty/openzeppelin/AccessControlUpgradeableLegacy.sol"; /** * @title Permissions * @dev Contract is connected module for Upgradeable approach, knows ContractManager */ contract Permissions is AccessControlUpgradeableLegacy, IPermissions { using AddressUpgradeable for address; IContractManager public contractManager; /** * @dev Modifier to make a function callable only when caller is the Owner. * * Requirements: * * - The caller must be the owner. */ modifier onlyOwner() { require(_isOwner(), "Caller is not the owner"); _; } /** * @dev Modifier to make a function callable only when caller is an Admin. * * Requirements: * * - The caller must be an admin. */ modifier onlyAdmin() { require(_isAdmin(msg.sender), "Caller is not an admin"); _; } /** * @dev Modifier to make a function callable only when caller is the Owner * or `contractName` contract. * * Requirements: * * - The caller must be the owner or `contractName`. */ modifier allow(string memory contractName) { require( contractManager.getContract(contractName) == msg.sender || _isOwner(), "Message sender is invalid"); _; } /** * @dev Modifier to make a function callable only when caller is the Owner * or `contractName1` or `contractName2` contract. * * Requirements: * * - The caller must be the owner, `contractName1`, or `contractName2`. */ modifier allowTwo(string memory contractName1, string memory contractName2) { require( contractManager.getContract(contractName1) == msg.sender || contractManager.getContract(contractName2) == msg.sender || _isOwner(), "Message sender is invalid"); _; } /** * @dev Modifier to make a function callable only when caller is the Owner * or `contractName1`, `contractName2`, or `contractName3` contract. * * Requirements: * * - The caller must be the owner, `contractName1`, `contractName2`, or * `contractName3`. */ modifier allowThree(string memory contractName1, string memory contractName2, string memory contractName3) { require( contractManager.getContract(contractName1) == msg.sender || contractManager.getContract(contractName2) == msg.sender || contractManager.getContract(contractName3) == msg.sender || _isOwner(), "Message sender is invalid"); _; } function initialize(address contractManagerAddress) public virtual override initializer { AccessControlUpgradeableLegacy.__AccessControl_init(); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); _setContractManager(contractManagerAddress); } function _isOwner() internal view returns (bool owner) { return hasRole(DEFAULT_ADMIN_ROLE, msg.sender); } function _isAdmin(address account) internal view returns (bool admin) { address skaleManagerAddress = contractManager.contracts(keccak256(abi.encodePacked("SkaleManager"))); if (skaleManagerAddress != address(0)) { AccessControlUpgradeableLegacy skaleManager = AccessControlUpgradeableLegacy(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 = IContractManager(contractManagerAddress); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; import "@skalenetwork/skale-manager-interfaces/thirdparty/openzeppelin/IAccessControlUpgradeableLegacy.sol"; import "./InitializableWithGap.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, _msgSender())); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. */ abstract contract AccessControlUpgradeableLegacy is InitializableWithGap, ContextUpgradeable, IAccessControlUpgradeableLegacy { function __AccessControl_init() internal initializer { __Context_init_unchained(); __AccessControl_init_unchained(); } function __AccessControl_init_unchained() internal initializer { } using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; struct RoleData { EnumerableSetUpgradeable.AddressSet members; bytes32 adminRole; } mapping (bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view override returns (bool) { return _roles[role].members.contains(account); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view override returns (uint256) { return _roles[role].members.length(); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view override returns (address) { return _roles[role].members.at(index); } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) public virtual override { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant"); _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) public virtual override { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke"); _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { _roles[role].adminRole = adminRole; } function _grantRole(bytes32 role, address account) private { if (_roles[role].members.add(account)) { emit RoleGranted(role, account, _msgSender()); } } function _revokeRole(bytes32 role, address account) private { if (_roles[role].members.remove(account)) { emit RoleRevoked(role, account, _msgSender()); } } uint256[49] private __gap; } // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.7; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract InitializableWithGap is Initializable { uint256[50] private ______gap; } // SPDX-License-Identifier: AGPL-3.0-only /* FractionUtils.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.8.17; library FractionUtils { struct Fraction { uint256 numerator; uint256 denominator; } function createFraction(uint256 numerator, uint256 denominator) internal pure returns (Fraction memory fraction) { require(denominator > 0, "Division by zero"); fraction = Fraction({numerator: numerator, denominator: denominator}); reduceFraction(fraction); return fraction; } function createFraction(uint256 value) internal pure returns (Fraction memory fraction) { return createFraction(value, 1); } function reduceFraction(Fraction memory fraction) internal pure { uint256 _gcd = gcd(fraction.numerator, fraction.denominator); fraction.numerator = fraction.numerator / _gcd; fraction.denominator = fraction.denominator / _gcd; } // numerator - is limited by 7*10^27, we could multiply it numerator * numerator - it would less than 2^256-1 function multiplyFraction(Fraction memory a, Fraction memory b) internal pure returns (Fraction memory fraction) { return createFraction(a.numerator * b.numerator, a.denominator * b.denominator); } function gcd(uint256 a, uint256 b) internal pure returns (uint256 value) { uint256 _a = a; uint256 _b = b; if (_b > _a) { (_a, _b) = swap(_a, _b); } while (_b > 0) { _a = _a % _b; (_a, _b) = swap (_a, _b); } return _a; } function swap(uint256 a, uint256 b) internal pure returns (uint256 left, uint256 right) { return (b, a); } } // SPDX-License-Identifier: AGPL-3.0-only /* MathUtils.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Dmytro Stebaiev SKALE Manager is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SKALE Manager is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with SKALE Manager. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.8.17; library MathUtils { uint256 constant private _EPS = 1e6; event UnderflowError( uint256 a, uint256 b ); function boundedSub(uint256 a, uint256 b) internal returns (uint256 value) { if (a >= b) { return a - b; } else { emit UnderflowError(a, b); return 0; } } function boundedSubWithoutEvent(uint256 a, uint256 b) internal pure returns (uint256 value) { if (a >= b) { return a - b; } else { return 0; } } function muchGreater(uint256 a, uint256 b) internal pure returns (bool result) { assert(type(uint).max - _EPS > b); return a > b + _EPS; } function approximatelyEqual(uint256 a, uint256 b) internal pure returns (bool result) { if (a > b) { return a - b < _EPS; } else { return b - a < _EPS; } } }