diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 386b7dfec..ac4e42776 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,4 +1,7 @@ /* eslint-env node */ + +// cspell:words venv + module.exports = { "extends": [ "eslint:recommended", @@ -6,7 +9,8 @@ module.exports = { ], "ignorePatterns": [ "coverage/**", - "typechain-types/**" + "typechain-types/**", + "venv/**" ], "env": { "node": true diff --git a/.solhint.json b/.solhint.json index 0c8a32ead..862c85182 100644 --- a/.solhint.json +++ b/.solhint.json @@ -3,10 +3,11 @@ "rules": { "not-rely-on-time": "off", + "compiler-version": ["warn","0.8.26"], + "avoid-tx-origin": "error", "check-send-result": "error", "code-complexity": "error", - "compiler-version": ["error","0.8.17"], "comprehensive-interface": "error", "contract-name-camelcase": "error", "explicit-types": "error", @@ -14,6 +15,7 @@ "func-named-parameters": "error", "func-visibility": ["error", {"ignoreConstructors": true}], "function-max-lines": "error", + "max-line-length": ["error", 100], "max-states-count": ["error", 20], "no-empty-blocks": "error", "no-global-import": "error", diff --git a/contracts/BountyV2.sol b/contracts/BountyV2.sol index 1bcd16110..0a7486f83 100644 --- a/contracts/BountyV2.sol +++ b/contracts/BountyV2.sol @@ -22,7 +22,9 @@ pragma solidity 0.8.17; import { IBountyV2 } from "@skalenetwork/skale-manager-interfaces/IBountyV2.sol"; -import { IDelegationController } from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; +import { + IDelegationController +} from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; import { ITimeHelpers } from "@skalenetwork/skale-manager-interfaces/delegation/ITimeHelpers.sol"; import { INodes } from "@skalenetwork/skale-manager-interfaces/INodes.sol"; @@ -51,7 +53,8 @@ contract BountyV2 is Permissions, IBountyV2 { uint256 public constant SECONDS_PER_DAY = 24 * 60 * 60; uint256 public constant BOUNTY_WINDOW_SECONDS = 3 * SECONDS_PER_DAY; - bytes32 public constant BOUNTY_REDUCTION_MANAGER_ROLE = keccak256("BOUNTY_REDUCTION_MANAGER_ROLE"); + bytes32 public constant BOUNTY_REDUCTION_MANAGER_ROLE = + keccak256("BOUNTY_REDUCTION_MANAGER_ROLE"); uint256 private _nextEpoch; uint256 private _epochPool; @@ -67,7 +70,10 @@ contract BountyV2 is Permissions, IBountyV2 { mapping (uint256 => BountyHistory) private _bountyHistory; modifier onlyBountyReductionManager() { - require(hasRole(BOUNTY_REDUCTION_MANAGER_ROLE, msg.sender), "BOUNTY_REDUCTION_MANAGER_ROLE is required"); + require( + hasRole(BOUNTY_REDUCTION_MANAGER_ROLE, msg.sender), + "BOUNTY_REDUCTION_MANAGER_ROLE is required" + ); _; } @@ -86,12 +92,12 @@ contract BountyV2 is Permissions, IBountyV2 { allow("SkaleManager") returns (uint256 bounty) { - ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); + ConstantsHolder constantsHolder = + ConstantsHolder(contractManager.getContract("ConstantsHolder")); INodes nodes = INodes(contractManager.getContract("Nodes")); ITimeHelpers timeHelpers = ITimeHelpers(contractManager.getContract("TimeHelpers")); - IDelegationController delegationController = IDelegationController( - contractManager.getContract("DelegationController") - ); + IDelegationController delegationController = + IDelegationController(contractManager.getContract("DelegationController")); require( _getNextRewardTimestamp(nodeIndex, nodes, timeHelpers) <= block.timestamp, @@ -171,7 +177,8 @@ contract BountyV2 is Permissions, IBountyV2 { } function estimateBounty(uint256 nodeIndex) external view override returns (uint256 bounty) { - ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); + ConstantsHolder constantsHolder = + ConstantsHolder(contractManager.getContract("ConstantsHolder")); INodes nodes = INodes(contractManager.getContract("Nodes")); ITimeHelpers timeHelpers = ITimeHelpers(contractManager.getContract("TimeHelpers")); IDelegationController delegationController = IDelegationController( @@ -187,17 +194,28 @@ contract BountyV2 is Permissions, IBountyV2 { return _calculateMaximumBountyAmount({ epochPoolSize: stagePoolSize, effectiveDelegatedSum: _effectiveDelegatedSum.getValue(currentMonth), - bountyWasPaidInCurrentEpoch: _nextEpoch == currentMonth + 1 ? _bountyWasPaidInCurrentEpoch : 0, + bountyWasPaidInCurrentEpoch: _nextEpoch == currentMonth + 1 ? + _bountyWasPaidInCurrentEpoch : + 0, nodeIndex: nodeIndex, bountyPaidToTheValidator: _getBountyPaid(validatorId, currentMonth), - effectiveDelegated: delegationController.getEffectiveDelegatedToValidator(validatorId, currentMonth), + effectiveDelegated: delegationController.getEffectiveDelegatedToValidator( + validatorId, currentMonth + ), delegated: delegationController.getDelegatedToValidator(validatorId, currentMonth), constantsHolder: constantsHolder, nodes: nodes }); } - function getNextRewardTimestamp(uint256 nodeIndex) external view override returns (uint256 timestamp) { + function getNextRewardTimestamp( + uint256 nodeIndex + ) + external + view + override + returns (uint256 timestamp) + { return _getNextRewardTimestamp( nodeIndex, INodes(contractManager.getContract("Nodes")), @@ -211,7 +229,13 @@ contract BountyV2 is Permissions, IBountyV2 { // private - function _refillEpochPool(uint256 currentMonth, ITimeHelpers timeHelpers, ConstantsHolder constantsHolder) private { + function _refillEpochPool( + uint256 currentMonth, + ITimeHelpers timeHelpers, + ConstantsHolder constantsHolder + ) + private + { uint256 epochPool; uint256 nextEpoch; (epochPool, nextEpoch) = _getEpochPool(currentMonth, timeHelpers, constantsHolder); @@ -354,7 +378,14 @@ contract BountyV2 is Permissions, IBountyV2 { } } - function _getBountyPaid(uint256 validatorId, uint256 month) private view returns (uint256 amount) { + function _getBountyPaid( + uint256 validatorId, + uint256 month + ) + private + view + returns (uint256 amount) + { require(_bountyHistory[validatorId].month <= month, "Can't get bounty paid"); if (_bountyHistory[validatorId].month == month) { return _bountyHistory[validatorId].bountyPaid; @@ -381,7 +412,10 @@ contract BountyV2 is Permissions, IBountyV2 { if (lastRewardTimestamp < lastRewardMonthStart + nodeCreationWindowSeconds) { return nextMonthStart - BOUNTY_WINDOW_SECONDS; } else { - return _min(nextMonthStart + timePassedAfterMonthStart, nextMonthFinish - BOUNTY_WINDOW_SECONDS); + return _min( + nextMonthStart + timePassedAfterMonthStart, + nextMonthFinish - BOUNTY_WINDOW_SECONDS + ); } } else if (lastRewardMonth + 1 == currentMonth) { uint256 currentMonthStart = timeHelpers.monthToTimestamp(currentMonth); diff --git a/contracts/CommonErrors.sol b/contracts/CommonErrors.sol new file mode 100644 index 000000000..cedccd39a --- /dev/null +++ b/contracts/CommonErrors.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/* + CommonErrors.sol - SKALE Manager + Copyright (C) 2024-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 . +*/ + +pragma solidity ^0.8.17; + + +error AddressIsNotSet(); +error GroupIndexIsInvalid(uint256 index); +error IsNotContract(address account); +error NotEnoughFunds(); +error RoleRequired(bytes32 role); diff --git a/contracts/ConstantsHolder.sol b/contracts/ConstantsHolder.sol index 745084653..25e706691 100644 --- a/contracts/ConstantsHolder.sol +++ b/contracts/ConstantsHolder.sol @@ -33,12 +33,12 @@ import { Permissions } from "./Permissions.sol"; contract ConstantsHolder is Permissions, IConstantsHolder { // initial price for creating Node (100 SKL) - uint256 public constant NODE_DEPOSIT = 100 * 1e18; + uint256 public constant override NODE_DEPOSIT = 100 * 1e18; - uint8 public constant TOTAL_SPACE_ON_NODE = 128; + uint8 public constant override TOTAL_SPACE_ON_NODE = 128; // part of Node for Small Skale-chain (1/128 of Node) - uint8 public constant SMALL_DIVISOR = 128; + uint8 public constant override SMALL_DIVISOR = 128; // part of Node for Medium Skale-chain (1/32 of Node) uint8 public constant MEDIUM_DIVISOR = 32; @@ -59,7 +59,7 @@ contract ConstantsHolder is Permissions, IConstantsHolder { uint256 public constant NUMBER_OF_NODES_FOR_MEDIUM_TEST_SCHAIN = 4; // number of seconds in one year - uint32 public constant SECONDS_TO_YEAR = 31622400; + uint32 public constant override SECONDS_TO_YEAR = 31622400; // initial number of monitors uint256 public constant NUMBER_OF_MONITORS = 24; @@ -130,10 +130,14 @@ contract ConstantsHolder is Permissions, IConstantsHolder { uint256 public minNodeBalance; - bytes32 public constant CONSTANTS_HOLDER_MANAGER_ROLE = keccak256("CONSTANTS_HOLDER_MANAGER_ROLE"); + bytes32 public constant CONSTANTS_HOLDER_MANAGER_ROLE = + keccak256("CONSTANTS_HOLDER_MANAGER_ROLE"); modifier onlyConstantsHolderManager() { - require(hasRole(CONSTANTS_HOLDER_MANAGER_ROLE, msg.sender), "CONSTANTS_HOLDER_MANAGER_ROLE is required"); + require( + hasRole(CONSTANTS_HOLDER_MANAGER_ROLE, msg.sender), + "CONSTANTS_HOLDER_MANAGER_ROLE is required" + ); _; } @@ -159,7 +163,14 @@ contract ConstantsHolder is Permissions, IConstantsHolder { * @dev Allows the Owner to set new reward and delta periods * This function is only for tests. */ - function setPeriods(uint32 newRewardPeriod, uint32 newDeltaPeriod) external override onlyConstantsHolderManager { + function setPeriods( + uint32 newRewardPeriod, + uint32 newDeltaPeriod + ) + external + override + onlyConstantsHolderManager + { require( newRewardPeriod >= newDeltaPeriod && newRewardPeriod - newDeltaPeriod >= checkTime, "Incorrect Periods" @@ -248,7 +259,13 @@ contract ConstantsHolder is Permissions, IConstantsHolder { /** * @dev Allows the Owner to set the proof-of-use lockup period. */ - function setProofOfUseLockUpPeriod(uint256 periodDays) external override onlyConstantsHolderManager { + function setProofOfUseLockUpPeriod( + uint256 periodDays + ) + external + override + onlyConstantsHolderManager + { emit ConstantUpdated( keccak256(abi.encodePacked("ProofOfUseLockUpPeriodDays")), uint(proofOfUseLockUpPeriodDays), @@ -261,7 +278,13 @@ contract ConstantsHolder is Permissions, IConstantsHolder { * @dev Allows the Owner to set the proof-of-use delegation percentage * requirement. */ - function setProofOfUseDelegationPercentage(uint256 percentage) external override onlyConstantsHolderManager { + function setProofOfUseDelegationPercentage( + uint256 percentage + ) + external + override + onlyConstantsHolderManager + { require(percentage <= 100, "Percentage value is incorrect"); emit ConstantUpdated( keccak256(abi.encodePacked("ProofOfUseDelegationPercentage")), @@ -275,7 +298,13 @@ contract ConstantsHolder is Permissions, IConstantsHolder { * @dev Allows the Owner to set the maximum number of validators that a * single delegator can delegate to. */ - function setLimitValidatorsPerDelegator(uint256 newLimit) external override onlyConstantsHolderManager { + function setLimitValidatorsPerDelegator( + uint256 newLimit + ) + external + override + onlyConstantsHolderManager + { emit ConstantUpdated( keccak256(abi.encodePacked("LimitValidatorsPerDelegator")), uint(limitValidatorsPerDelegator), @@ -284,7 +313,13 @@ contract ConstantsHolder is Permissions, IConstantsHolder { limitValidatorsPerDelegator = newLimit; } - function setSchainCreationTimeStamp(uint256 timestamp) external override onlyConstantsHolderManager { + function setSchainCreationTimeStamp( + uint256 timestamp + ) + external + override + onlyConstantsHolderManager + { emit ConstantUpdated( keccak256(abi.encodePacked("SchainCreationTimeStamp")), uint(schainCreationTimeStamp), @@ -293,7 +328,13 @@ contract ConstantsHolder is Permissions, IConstantsHolder { schainCreationTimeStamp = timestamp; } - function setMinimalSchainLifetime(uint256 lifetime) external override onlyConstantsHolderManager { + function setMinimalSchainLifetime( + uint256 lifetime + ) + external + override + onlyConstantsHolderManager + { emit ConstantUpdated( keccak256(abi.encodePacked("MinimalSchainLifetime")), uint(minimalSchainLifetime), @@ -302,7 +343,13 @@ contract ConstantsHolder is Permissions, IConstantsHolder { minimalSchainLifetime = lifetime; } - function setComplaintTimeLimit(uint256 timeLimit) external override onlyConstantsHolderManager { + function setComplaintTimeLimit( + uint256 timeLimit + ) + external + override + onlyConstantsHolderManager + { emit ConstantUpdated( keccak256(abi.encodePacked("ComplaintTimeLimit")), uint(complaintTimeLimit), @@ -311,7 +358,13 @@ contract ConstantsHolder is Permissions, IConstantsHolder { complaintTimeLimit = timeLimit; } - function setMinNodeBalance(uint256 newMinNodeBalance) external override onlyConstantsHolderManager { + function setMinNodeBalance( + uint256 newMinNodeBalance + ) + external + override + onlyConstantsHolderManager + { emit ConstantUpdated( keccak256(abi.encodePacked("MinNodeBalance")), uint(minNodeBalance), diff --git a/contracts/ContractManager.sol b/contracts/ContractManager.sol index 2faa006b3..3f836f84a 100644 --- a/contracts/ContractManager.sol +++ b/contracts/ContractManager.sol @@ -21,8 +21,12 @@ pragma solidity 0.8.17; -import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import { AddressUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; +import { + OwnableUpgradeable +} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { + AddressUpgradeable +} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import { IContractManager } from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; import { StringUtils } from "./utils/StringUtils.sol"; @@ -91,7 +95,12 @@ contract ContractManager is InitializableWithGap, OwnableUpgradeable, IContractM * * - Contract must exist. */ - function getDelegationPeriodManager() external view override returns (address delegationPeriodManager) { + function getDelegationPeriodManager() + external + view + override + returns (address delegationPeriodManager) + { return getContract(DELEGATION_PERIOD_MANAGER); } @@ -123,7 +132,14 @@ contract ContractManager is InitializableWithGap, OwnableUpgradeable, IContractM return getContract(PUNISHER); } - function getContract(string memory name) public view override returns (address contractAddress) { + 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")); diff --git a/contracts/Decryption.sol b/contracts/Decryption.sol index 77e17f6c1..d526ed8d0 100644 --- a/contracts/Decryption.sol +++ b/contracts/Decryption.sol @@ -34,14 +34,30 @@ contract Decryption is IDecryption { /** * @dev Returns an encrypted text given a secret and a key. */ - function encrypt(uint256 secretNumber, bytes32 key) external pure override returns (bytes32 cipherText) { + function encrypt( + uint256 secretNumber, + bytes32 key + ) + external + pure + override + returns (bytes32 cipherText) + { return bytes32(secretNumber) ^ key; } /** * @dev Returns a secret given an encrypted text and a key. */ - function decrypt(bytes32 cipherText, bytes32 key) external pure override returns (uint256 secretNumber) { + function decrypt( + bytes32 cipherText, + bytes32 key + ) + external + pure + override + returns (uint256 secretNumber) + { return uint256(cipherText ^ key); } } diff --git a/contracts/KeyStorage.sol b/contracts/KeyStorage.sol index b4837396e..16139eb14 100644 --- a/contracts/KeyStorage.sol +++ b/contracts/KeyStorage.sol @@ -21,12 +21,12 @@ pragma solidity 0.8.17; -import { IKeyStorage } from "@skalenetwork/skale-manager-interfaces/IKeyStorage.sol"; -import { ISkaleDKG } from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; +import {IKeyStorage} from "@skalenetwork/skale-manager-interfaces/IKeyStorage.sol"; +import {ISkaleDKG} from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; -import { Permissions } from "./Permissions.sol"; -import { Fp2Operations } from "./utils/fieldOperations/Fp2Operations.sol"; -import { G2Operations } from "./utils/fieldOperations/G2Operations.sol"; +import {Permissions} from "./Permissions.sol"; +import {Fp2Operations} from "./utils/fieldOperations/Fp2Operations.sol"; +import {G2Operations} from "./utils/fieldOperations/G2Operations.sol"; contract KeyStorage is Permissions, IKeyStorage { using Fp2Operations for ISkaleDKG.Fp2Point; @@ -55,24 +55,37 @@ contract KeyStorage is Permissions, IKeyStorage { } function deleteKey(bytes32 schainHash) external override allow("SkaleDKG") { - _previousSchainsPublicKeys[schainHash].push(_schainsPublicKeys[schainHash]); + _previousSchainsPublicKeys[schainHash].push( + _schainsPublicKeys[schainHash] + ); delete _schainsPublicKeys[schainHash]; delete _data[schainHash][0]; delete _schainsNodesPublicKeys[schainHash]; } - function initPublicKeyInProgress(bytes32 schainHash) external override allow("SkaleDKG") { + function initPublicKeyInProgress( + bytes32 schainHash + ) external override allow("SkaleDKG") { _publicKeysInProgress[schainHash] = G2Operations.getG2Zero(); } - function adding(bytes32 schainHash, ISkaleDKG.G2Point memory value) external override allow("SkaleDKG") { + function adding( + bytes32 schainHash, + ISkaleDKG.G2Point memory value + ) external override allow("SkaleDKG") { require(value.isG2(), "Incorrect g2 point"); - _publicKeysInProgress[schainHash] = value.addG2(_publicKeysInProgress[schainHash]); + _publicKeysInProgress[schainHash] = value.addG2( + _publicKeysInProgress[schainHash] + ); } - function finalizePublicKey(bytes32 schainHash) external override allow("SkaleDKG") { + function finalizePublicKey( + bytes32 schainHash + ) external override allow("SkaleDKG") { if (!_isSchainsPublicKeyZero(schainHash)) { - _previousSchainsPublicKeys[schainHash].push(_schainsPublicKeys[schainHash]); + _previousSchainsPublicKeys[schainHash].push( + _schainsPublicKeys[schainHash] + ); } _schainsPublicKeys[schainHash] = _publicKeysInProgress[schainHash]; delete _publicKeysInProgress[schainHash]; @@ -80,12 +93,7 @@ contract KeyStorage is Permissions, IKeyStorage { function getCommonPublicKey( bytes32 schainHash - ) - external - view - override - returns (ISkaleDKG.G2Point memory publicKey) - { + ) external view override returns (ISkaleDKG.G2Point memory publicKey) { return _schainsPublicKeys[schainHash]; } @@ -115,8 +123,11 @@ contract KeyStorage is Permissions, IKeyStorage { return _previousSchainsPublicKeys[schainHash]; } - function _isSchainsPublicKeyZero(bytes32 schainHash) private view returns (bool zero) { - return _schainsPublicKeys[schainHash].x.a == 0 && + function _isSchainsPublicKeyZero( + bytes32 schainHash + ) private view returns (bool zero) { + return + _schainsPublicKeys[schainHash].x.a == 0 && _schainsPublicKeys[schainHash].x.b == 0 && _schainsPublicKeys[schainHash].y.a == 0 && _schainsPublicKeys[schainHash].y.b == 0; diff --git a/contracts/NodeRotation.sol b/contracts/NodeRotation.sol index 2a1360085..3362512a8 100644 --- a/contracts/NodeRotation.sol +++ b/contracts/NodeRotation.sol @@ -100,7 +100,8 @@ contract NodeRotation is Permissions, INodeRotation { allow("SkaleManager") returns (bool contains, bool successful) { - ISchainsInternal schainsInternal = ISchainsInternal(contractManager.getContract("SchainsInternal")); + ISchainsInternal schainsInternal = + ISchainsInternal(contractManager.getContract("SchainsInternal")); bytes32 schainHash = schainsInternal.getActiveSchain(nodeIndex); if (schainHash == bytes32(0)) { return (true, false); @@ -144,7 +145,14 @@ contract NodeRotation is Permissions, INodeRotation { /** * @dev Returns rotation details for a given schain. */ - function getRotation(bytes32 schainHash) external view override returns (INodeRotation.Rotation memory rotation) { + function getRotation( + bytes32 schainHash + ) + external + view + override + returns (INodeRotation.Rotation memory rotation) + { return Rotation({ nodeIndex: _rotations[schainHash].nodeIndex, newNodeIndex: _rotations[schainHash].newNodeIndex, @@ -167,7 +175,14 @@ contract NodeRotation is Permissions, INodeRotation { return leavingHistory[nodeIndex]; } - function isRotationInProgress(bytes32 schainHash) external view override returns (bool inProgress) { + function isRotationInProgress( + bytes32 schainHash + ) + external + view + override + returns (bool inProgress) + { bool foundNewNode = isNewNodeFound(schainHash); return foundNewNode ? leavingHistory[_rotations[schainHash].nodeIndex][ @@ -181,7 +196,15 @@ contract NodeRotation is Permissions, INodeRotation { * If there is no previous node for given node would return an error: * "No previous node" */ - function getPreviousNode(bytes32 schainHash, uint256 nodeIndex) external view override returns (uint256 node) { + function getPreviousNode( + bytes32 schainHash, + uint256 nodeIndex + ) + external + view + override + returns (uint256 node) + { require(_rotations[schainHash].newNodeIndexes.contains(nodeIndex), "No previous node"); return _rotations[schainHash].previousNodes[nodeIndex]; } @@ -201,7 +224,8 @@ contract NodeRotation is Permissions, INodeRotation { allowThree("SkaleDKG", "SkaleManager", "Schains") returns (uint256 newNode) { - ISchainsInternal schainsInternal = ISchainsInternal(contractManager.getContract("SchainsInternal")); + ISchainsInternal schainsInternal = + ISchainsInternal(contractManager.getContract("SchainsInternal")); schainsInternal.removeNodeFromSchain(nodeIndex, schainHash); if (!isBadNode) { schainsInternal.removeNodeFromExceptions(schainHash, nodeIndex); @@ -226,7 +250,8 @@ contract NodeRotation is Permissions, INodeRotation { allowThree("SkaleManager", "Schains", "SkaleDKG") returns (uint256 nodeIndex) { - ISchainsInternal schainsInternal = ISchainsInternal(contractManager.getContract("SchainsInternal")); + ISchainsInternal schainsInternal = + ISchainsInternal(contractManager.getContract("SchainsInternal")); INodes nodes = INodes(contractManager.getContract("Nodes")); require(schainsInternal.isSchainActive(schainHash), "Group is not active"); uint8 space = schainsInternal.getSchainsPartOfNode(schainHash); @@ -236,7 +261,10 @@ contract NodeRotation is Permissions, INodeRotation { abi.encodePacked(uint256(blockhash(block.number - 1)), schainHash) ); nodeIndex = nodes.getRandomNodeWithFreeSpace(space, randomGenerator); - require(nodes.removeSpaceFromNode(nodeIndex, space), "Could not remove space from nodeIndex"); + require( + nodes.removeSpaceFromNode(nodeIndex, space), + "Could not remove space from nodeIndex" + ); schainsInternal.makeSchainNodesVisible(schainHash); schainsInternal.addSchainForNode(nodes, nodeIndex, schainHash); schainsInternal.setException(schainHash, nodeIndex); @@ -244,9 +272,11 @@ contract NodeRotation is Permissions, INodeRotation { } function isNewNodeFound(bytes32 schainHash) public view override returns (bool found) { - return _rotations[schainHash].newNodeIndexes.contains(_rotations[schainHash].newNodeIndex) && - _rotations[schainHash].previousNodes[_rotations[schainHash].newNodeIndex] == - _rotations[schainHash].nodeIndex; + return _rotations[schainHash] + .newNodeIndexes.contains(_rotations[schainHash].newNodeIndex) && + _rotations[schainHash] + .previousNodes[_rotations[schainHash].newNodeIndex] == + _rotations[schainHash].nodeIndex; } @@ -259,7 +289,8 @@ contract NodeRotation is Permissions, INodeRotation { } function _startWaiting(bytes32 schainHash, uint256 nodeIndex) private { - IConstantsHolder constants = IConstantsHolder(contractManager.getContract("ConstantsHolder")); + IConstantsHolder constants = + IConstantsHolder(contractManager.getContract("ConstantsHolder")); _rotations[schainHash].nodeIndex = nodeIndex; _rotations[schainHash].freezeUntil = block.timestamp + constants.rotationDelay(); } @@ -277,16 +308,20 @@ contract NodeRotation is Permissions, INodeRotation { // During skaled config generation skale-admin relies on a fact that // for each pair of nodes swaps (rotations) the more new swap has bigger finish_ts value. - // Also skale-admin supposes that if the different between finish_ts is minimum possible (1 second) + // Also skale-admin supposes that + // if the different between finish_ts is minimum possible (1 second) // the corresponding swap was cased by failed DKG and no proper keys were generated. uint256 finishTimestamp; if (shouldDelay) { finishTimestamp = block.timestamp + - IConstantsHolder(contractManager.getContract("ConstantsHolder")).rotationDelay(); + IConstantsHolder( + contractManager.getContract("ConstantsHolder") + ).rotationDelay(); } else { if(_rotations[schainHash].rotationCounter > 0) { - uint256 previousRotatedNode = _rotations[schainHash].previousNodes[_rotations[schainHash].newNodeIndex]; + uint256 previousRotatedNode = + _rotations[schainHash].previousNodes[_rotations[schainHash].newNodeIndex]; uint256 previousRotationTimestamp = leavingHistory[previousRotatedNode][ _rotations[schainHash].indexInLeavingHistory[previousRotatedNode] ].finishedRotation; @@ -295,13 +330,20 @@ contract NodeRotation is Permissions, INodeRotation { finishTimestamp = block.timestamp; } } - leavingHistory[nodeIndex].push(LeavingHistory({schainHash: schainHash, finishedRotation: finishTimestamp})); - require(_rotations[schainHash].newNodeIndexes.add(newNodeIndex), "New node was already added"); + leavingHistory[nodeIndex].push(LeavingHistory({ + schainHash: schainHash, + finishedRotation: finishTimestamp + })); + require( + _rotations[schainHash].newNodeIndexes.add(newNodeIndex), + "New node was already added" + ); _rotations[schainHash].nodeIndex = nodeIndex; _rotations[schainHash].newNodeIndex = newNodeIndex; _rotations[schainHash].rotationCounter++; _rotations[schainHash].previousNodes[newNodeIndex] = nodeIndex; - _rotations[schainHash].indexInLeavingHistory[nodeIndex] = leavingHistory[nodeIndex].length - 1; + _rotations[schainHash].indexInLeavingHistory[nodeIndex] = + leavingHistory[nodeIndex].length - 1; delete waitForNewNode[schainHash]; ISkaleDKG(contractManager.getContract("SkaleDKG")).openChannel(schainHash); } @@ -314,7 +356,10 @@ contract NodeRotation is Permissions, INodeRotation { if (_rotations[schainHash].freezeUntil < block.timestamp) { _startWaiting(schainHash, nodeIndex); } else { - require(_rotations[schainHash].nodeIndex == nodeIndex, "Occupied by rotation on Schain"); + require( + _rotations[schainHash].nodeIndex == nodeIndex, + "Occupied by rotation on Schain" + ); } } } diff --git a/contracts/Nodes.sol b/contracts/Nodes.sol index a4240a254..c5fe28d23 100644 --- a/contracts/Nodes.sol +++ b/contracts/Nodes.sol @@ -21,21 +21,32 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; +pragma solidity 0.8.26; -import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; +import { + SafeCastUpgradeable +} from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; import { INodes } from "@skalenetwork/skale-manager-interfaces/INodes.sol"; -import { IDelegationController } from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; -import { IValidatorService } from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; +import { + IDelegationController +} from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; +import { + IValidatorService +} from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; import { IBountyV2 } from "@skalenetwork/skale-manager-interfaces/IBountyV2.sol"; +import { + IPaymasterController +} from "@skalenetwork/skale-manager-interfaces/IPaymasterController.sol"; +import { IConstantsHolder } from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; +import { INodeRotation } from "@skalenetwork/skale-manager-interfaces/INodeRotation.sol"; import { Permissions } from "./Permissions.sol"; -import { ConstantsHolder } from "./ConstantsHolder.sol"; + import { IRandom, Random } from "./utils/Random.sol"; +import { RoleRequired } from "./CommonErrors.sol"; import { SegmentTree } from "./utils/SegmentTree.sol"; - -import { NodeRotation } from "./NodeRotation.sol"; +import { ValidatorDoesNotExist, ValidatorIsNotAuthorized } from "./delegation/ValidatorService.sol"; /** @@ -94,6 +105,20 @@ contract Nodes is Permissions, INodes { mapping(uint256 => NodeExtras) public nodeExtras; + error IpIsNotAvailable(bytes4 ip); + error NameIsAlreadyRegistered(string name); + error PortIsNotSet(); + error PublicKeyIsIncorrect(bytes32[2] key); + error NodeNotFound(); + error NodeDoesNotExist(uint256 nodeId); + error NodeIsNotActive(uint256 nodeId); + error NodeIsNotLeaving(uint256 nodeId); + error NodeIsNotInMaintenance(uint256 nodeId); + error MinimumStakingRequirementIsNotMet(); + error NodeDoesNotExistForValidator(uint256 validatorId, uint256 nodeId); + error IpAndPublicIpIsDifferent(bytes4 ip, bytes4 publicIp); + error SenderIsNotPermitted(address sender); + modifier checkNodeExists(uint256 nodeIndex) { _checkNodeIndex(nodeIndex); _; @@ -105,12 +130,16 @@ contract Nodes is Permissions, INodes { } modifier onlyCompliance() { - require(hasRole(COMPLIANCE_ROLE, msg.sender), "COMPLIANCE_ROLE is required"); + if (!hasRole(COMPLIANCE_ROLE, msg.sender)) { + revert RoleRequired(COMPLIANCE_ROLE); + } _; } modifier nonZeroIP(bytes4 ip) { - require(ip != 0x0 && !nodesIPCheck[ip], "IP address is zero or is not available"); + if (ip == 0x0 || nodesIPCheck[ip]) { + revert IpIsNotAvailable(ip); + } _; } @@ -214,38 +243,22 @@ contract Nodes is Permissions, INodes { nonZeroIP(params.ip) { // checks that Node has correct data - require(!nodesNameCheck[keccak256(abi.encodePacked(params.name))], "Name is already registered"); - require(params.port > 0, "Port is zero"); - require(from == _publicKeyToAddress(params.publicKey), "Public Key is incorrect"); + if (nodesNameCheck[keccak256(abi.encodePacked(params.name))]) { + revert NameIsAlreadyRegistered(params.name); + } + if (params.port == 0) { + revert PortIsNotSet(); + } + if (from != _publicKeyToAddress(params.publicKey)) { + revert PublicKeyIsIncorrect(params.publicKey); + } + uint256 validatorId = IValidatorService( contractManager.getContract("ValidatorService")).getValidatorIdByNodeAddress(from); - uint8 totalSpace = ConstantsHolder(contractManager.getContract("ConstantsHolder")).TOTAL_SPACE_ON_NODE(); - nodes.push(Node({ - name: params.name, - ip: params.ip, - publicIP: params.publicIp, - port: params.port, - publicKey: params.publicKey, - startBlock: block.number, - lastRewardDate: block.timestamp, - finishTime: 0, - status: NodeStatus.Active, - validatorId: validatorId - })); - uint256 nodeIndex = nodes.length - 1; - validatorToNodeIndexes[validatorId].push(nodeIndex); - bytes32 nodeHashName = keccak256(abi.encodePacked(params.name)); - nodesIPCheck[params.ip] = true; - nodesNameCheck[nodeHashName] = true; - nodesNameToIndex[nodeHashName] = nodeIndex; - nodeIndexes[from].isNodeExist[nodeIndex] = true; - nodeIndexes[from].numberOfNodes++; - domainNames[nodeIndex] = params.domainName; - spaceOfNodes.push(SpaceManaging({ - freeSpace: totalSpace, - indexInSpaceMap: spaceToNodes[totalSpace].length - })); + + uint256 nodeIndex = _addNode(validatorId, from, params); _setNodeActive(nodeIndex); + emit NodeCreated({ nodeIndex: nodeIndex, owner: from, @@ -256,6 +269,10 @@ contract Nodes is Permissions, INodes { nonce: params.nonce, domainName: params.domainName }); + + IPaymasterController paymasterController = + IPaymasterController(contractManager.getContract("PaymasterController")); + paymasterController.setNodesAmount(validatorId, validatorToNodeIndexes[validatorId].length); } /** @@ -270,10 +287,14 @@ contract Nodes is Permissions, INodes { override checkNodeExists(nodeIndex) { - require(hasRole(NODE_MANAGER_ROLE, msg.sender), "NODE_MANAGER_ROLE is required"); - require(isNodeActive(nodeIndex), "Node should be Active"); + if (!hasRole(NODE_MANAGER_ROLE, msg.sender)) { + revert RoleRequired(NODE_MANAGER_ROLE); + } + if (!isNodeActive(nodeIndex)) { + revert NodeIsNotActive(nodeIndex); + } _setNodeLeaving(nodeIndex); - NodeRotation(contractManager.getContract("NodeRotation")).freezeSchains(nodeIndex); + INodeRotation(contractManager.getContract("NodeRotation")).freezeSchains(nodeIndex); emit ExitInitialized(nodeIndex, block.timestamp); } @@ -295,7 +316,9 @@ contract Nodes is Permissions, INodes { allow("SkaleManager") returns (bool successful) { - require(isNodeLeaving(nodeIndex), "Node is not Leaving"); + if (!isNodeLeaving(nodeIndex)) { + revert NodeIsNotLeaving(nodeIndex); + } _setNodeLeft(nodeIndex); @@ -316,8 +339,11 @@ contract Nodes is Permissions, INodes { checkNodeExists(nodeIndex) allow("SkaleManager") { - IValidatorService validatorService = IValidatorService(contractManager.getValidatorService()); - require(validatorService.validatorExists(validatorId), "Validator ID does not exist"); + IValidatorService validatorService = + IValidatorService(contractManager.getValidatorService()); + if (!validatorService.validatorExists(validatorId)) { + revert ValidatorDoesNotExist(validatorId); + } uint256[] memory validatorNodes = validatorToNodeIndexes[validatorId]; uint256 position = _findNode(validatorNodes, nodeIndex); if (position < validatorNodes.length) { @@ -326,7 +352,8 @@ contract Nodes is Permissions, INodes { } validatorToNodeIndexes[validatorId].pop(); address nodeOwner = _publicKeyToAddress(nodes[nodeIndex].publicKey); - uint256 validatorIdByNode = validatorService.getValidatorIdByNodeAddressWithoutRevert(nodeOwner); + uint256 validatorIdByNode = + validatorService.getValidatorIdByNodeAddressWithoutRevert(nodeOwner); if (validatorIdByNode == validatorId || validatorIdByNode == 0) { if (nodeIndexes[nodeOwner].numberOfNodes == 1 && !validatorService.validatorAddressExists(nodeOwner) && @@ -337,6 +364,12 @@ contract Nodes is Permissions, INodes { nodeIndexes[nodeOwner].isNodeExist[nodeIndex] = false; nodeIndexes[nodeOwner].numberOfNodes--; } + + IPaymasterController paymasterController = + IPaymasterController(contractManager.getContract("PaymasterController")); + // in order to do not read validatorToNodeIndexes.length + // we use validatorNodes but it's length is 1 more. + paymasterController.setNodesAmount(validatorId, validatorNodes.length - 1); } /** @@ -348,13 +381,25 @@ contract Nodes is Permissions, INodes { * - Validator must be included on trusted list if trusted list is enabled. * - Validator must have sufficient stake to operate an additional node. */ - function checkPossibilityCreatingNode(address nodeAddress) external override allow("SkaleManager") { - IValidatorService validatorService = IValidatorService(contractManager.getValidatorService()); + function checkPossibilityCreatingNode( + address nodeAddress + ) + external + override + allow("SkaleManager") + { + IValidatorService validatorService = + IValidatorService(contractManager.getValidatorService()); uint256 validatorId = validatorService.getValidatorIdByNodeAddress(nodeAddress); - require(validatorService.isAuthorizedValidator(validatorId), "Validator is not authorized to create a node"); - require( - _checkValidatorPositionToMaintainNode(validatorId, validatorToNodeIndexes[validatorId].length), - "Validator must meet the Minimum Staking Requirement"); + if (!validatorService.isAuthorizedValidator(validatorId)) { + revert ValidatorIsNotAuthorized(validatorId); + } + if (!_checkValidatorPositionToMaintainNode( + validatorId, + validatorToNodeIndexes[validatorId].length + )) { + revert MinimumStakingRequirementIsNotMet(); + } } /** @@ -377,11 +422,16 @@ contract Nodes is Permissions, INodes { allow("Bounty") returns (bool successful) { - IValidatorService validatorService = IValidatorService(contractManager.getValidatorService()); - require(validatorService.validatorExists(validatorId), "Validator ID does not exist"); + IValidatorService validatorService = + IValidatorService(contractManager.getValidatorService()); + if (!validatorService.validatorExists(validatorId)) { + revert ValidatorDoesNotExist(validatorId); + } uint256[] memory validatorNodes = validatorToNodeIndexes[validatorId]; uint256 position = _findNode(validatorNodes, nodeIndex); - require(position < validatorNodes.length, "Node does not exist for this Validator"); + if (position >= validatorNodes.length) { + revert NodeDoesNotExistForValidator(validatorId, nodeIndex); + } return _checkValidatorPositionToMaintainNode(validatorId, position); } @@ -393,8 +443,16 @@ contract Nodes is Permissions, INodes { * - Node must already be Active. * - `msg.sender` must be owner of Node, validator, or SkaleManager. */ - function setNodeInMaintenance(uint256 nodeIndex) external override onlyNodeOrNodeManager(nodeIndex) { - require(nodes[nodeIndex].status == NodeStatus.Active, "Node is not Active"); + function setNodeInMaintenance( + uint256 nodeIndex + ) + external + override + onlyNodeOrNodeManager(nodeIndex) + { + if (!(nodes[nodeIndex].status == NodeStatus.Active)) { + revert NodeIsNotActive(nodeIndex); + } _setNodeInMaintenance(nodeIndex); emit MaintenanceNode(nodeIndex, true); } @@ -407,8 +465,16 @@ contract Nodes is Permissions, INodes { * - Node must already be In Maintenance. * - `msg.sender` must be owner of Node, validator, or SkaleManager. */ - function removeNodeFromInMaintenance(uint256 nodeIndex) external override onlyNodeOrNodeManager(nodeIndex) { - require(nodes[nodeIndex].status == NodeStatus.In_Maintenance, "Node is not In Maintenance"); + function removeNodeFromInMaintenance( + uint256 nodeIndex + ) + external + override + onlyNodeOrNodeManager(nodeIndex) + { + if (!(nodes[nodeIndex].status == NodeStatus.In_Maintenance)) { + revert NodeIsNotInMaintenance(nodeIndex); + } _setNodeActive(nodeIndex); emit MaintenanceNode(nodeIndex, false); } @@ -417,7 +483,14 @@ contract Nodes is Permissions, INodes { * @dev Marks the node as incompliant * */ - function setNodeIncompliant(uint256 nodeIndex) external override onlyCompliance checkNodeExists(nodeIndex) { + function setNodeIncompliant( + uint256 nodeIndex + ) + external + override + onlyCompliance + checkNodeExists(nodeIndex) + { if (!incompliant[nodeIndex]) { incompliant[nodeIndex] = true; _makeNodeInvisible(nodeIndex); @@ -429,7 +502,14 @@ contract Nodes is Permissions, INodes { * @dev Marks the node as compliant * */ - function setNodeCompliant(uint256 nodeIndex) external override onlyCompliance checkNodeExists(nodeIndex) { + function setNodeCompliant( + uint256 nodeIndex + ) + external + override + onlyCompliance + checkNodeExists(nodeIndex) + { if (incompliant[nodeIndex]) { incompliant[nodeIndex] = false; _tryToMakeNodeVisible(nodeIndex); @@ -465,7 +545,9 @@ contract Nodes is Permissions, INodes { nonZeroIP(newIP) { if (newPublicIP != 0x0) { - require(newIP == newPublicIP, "IP address is not the same"); + if (newIP != newPublicIP) { + revert IpAndPublicIpIsDifferent(newIP, newPublicIP); + } nodes[nodeIndex].publicIP = newPublicIP; } nodesIPCheck[nodes[nodeIndex].ip] = false; @@ -488,7 +570,9 @@ contract Nodes is Permissions, INodes { freeSpace == 0 ? 1 : freeSpace, randomGenerator ).toUint8(); - require(place > 0, "Node not found"); + if (place == 0) { + revert NodeNotFound(); + } return spaceToNodes[place][randomGenerator.random(spaceToNodes[place].length)]; } @@ -502,7 +586,9 @@ contract Nodes is Permissions, INodes { checkNodeExists(nodeIndex) returns (bool timeForReward) { - return IBountyV2(contractManager.getBounty()).getNextRewardTimestamp(nodeIndex) <= block.timestamp; + return IBountyV2( + contractManager.getBounty() + ).getNextRewardTimestamp(nodeIndex) <= block.timestamp; } /** @@ -519,7 +605,6 @@ contract Nodes is Permissions, INodes { checkNodeExists(nodeIndex) returns (bytes4 ip) { - require(nodeIndex < nodes.length, "Node does not exist"); return nodes[nodeIndex].ip; } @@ -668,7 +753,8 @@ contract Nodes is Permissions, INodes { function getActiveNodeIds() external view override returns (uint256[] memory activeNodeIds) { activeNodeIds = new uint256[](numberOfActiveNodes); uint256 indexOfActiveNodeIds = 0; - for (uint256 indexOfNodes = 0; indexOfNodes < nodes.length; indexOfNodes++) { + uint256 nodesLength = nodes.length; + for (uint256 indexOfNodes = 0; indexOfNodes < nodesLength; indexOfNodes++) { if (isNodeActive(indexOfNodes)) { activeNodeIds[indexOfActiveNodeIds] = indexOfNodes; indexOfActiveNodeIds++; @@ -704,15 +790,25 @@ contract Nodes is Permissions, INodes { override returns (uint256[] memory validatorNodes) { - IValidatorService validatorService = IValidatorService(contractManager.getValidatorService()); - require(validatorService.validatorExists(validatorId), "Validator ID does not exist"); + IValidatorService validatorService = + IValidatorService(contractManager.getValidatorService()); + if (!validatorService.validatorExists(validatorId)) { + revert ValidatorDoesNotExist(validatorId); + } return validatorToNodeIndexes[validatorId]; } /** * @dev Returns number of nodes with available space. */ - function countNodesWithFreeSpace(uint8 freeSpace) external view override returns (uint256 count) { + function countNodesWithFreeSpace( + uint8 freeSpace + ) + external + view + override + returns (uint256 count) + { if (freeSpace == 0) { return _nodesAmountBySpace.sumFromPlaceToLast(1); } @@ -932,24 +1028,69 @@ contract Nodes is Permissions, INodes { IDelegationController delegationController = IDelegationController( contractManager.getContract("DelegationController") ); - uint256 delegationsTotal = delegationController.getAndUpdateDelegatedToValidatorNow(validatorId); - uint256 msr = ConstantsHolder(contractManager.getConstantsHolder()).msr(); + uint256 delegationsTotal = + delegationController.getAndUpdateDelegatedToValidatorNow(validatorId); + uint256 msr = IConstantsHolder(contractManager.getConstantsHolder()).msr(); return (position + 1) * msr <= delegationsTotal; } + function _addNode( + uint256 validatorId, + address nodeAddress, + NodeCreationParams calldata params + ) + private + returns (uint256 nodeIndex) + { + nodes.push(Node({ + name: params.name, + ip: params.ip, + publicIP: params.publicIp, + port: params.port, + publicKey: params.publicKey, + startBlock: block.number, + lastRewardDate: block.timestamp, + finishTime: 0, + status: NodeStatus.Active, + validatorId: validatorId + })); + + uint8 totalSpace = IConstantsHolder( + contractManager.getContract("ConstantsHolder") + ).TOTAL_SPACE_ON_NODE(); + + nodeIndex = nodes.length - 1; + validatorToNodeIndexes[validatorId].push(nodeIndex); + bytes32 nodeHashName = keccak256(abi.encodePacked(params.name)); + nodesIPCheck[params.ip] = true; + nodesNameCheck[nodeHashName] = true; + nodesNameToIndex[nodeHashName] = nodeIndex; + nodeIndexes[nodeAddress].isNodeExist[nodeIndex] = true; + nodeIndexes[nodeAddress].numberOfNodes++; + domainNames[nodeIndex] = params.domainName; + spaceOfNodes.push(SpaceManaging({ + freeSpace: totalSpace, + indexInSpaceMap: spaceToNodes[totalSpace].length + })); + } + function _checkNodeIndex(uint256 nodeIndex) private view { - require(nodeIndex < nodes.length, "Node with such index does not exist"); + if (nodeIndex >= nodes.length) { + revert NodeDoesNotExist(nodeIndex); + } } function _checkNodeOrNodeManager(uint256 nodeIndex, address sender) private view { - IValidatorService validatorService = IValidatorService(contractManager.getValidatorService()); - - require( - isNodeExist(sender, nodeIndex) || - hasRole(NODE_MANAGER_ROLE, msg.sender) || - getValidatorId(nodeIndex) == validatorService.getValidatorId(sender), - "Sender is not permitted to call this function" - ); + IValidatorService validatorService = + IValidatorService(contractManager.getValidatorService()); + + if ( + !isNodeExist(sender, nodeIndex) && + !hasRole(NODE_MANAGER_ROLE, msg.sender) && + !(getValidatorId(nodeIndex) == validatorService.getValidatorId(sender)) + ) { + revert SenderIsNotPermitted(sender); + } } function _canBeVisible(uint256 nodeIndex) private view returns (bool can) { @@ -959,7 +1100,14 @@ contract Nodes is Permissions, INodes { /** * @dev Returns the index of a given node within the validator's node index. */ - function _findNode(uint256[] memory validatorNodeIndexes, uint256 nodeIndex) private pure returns (uint256 node) { + function _findNode( + uint256[] memory validatorNodeIndexes, + uint256 nodeIndex + ) + private + pure + returns (uint256 node) + { uint256 i; for (i = 0; i < validatorNodeIndexes.length; i++) { if (validatorNodeIndexes[i] == nodeIndex) { @@ -969,7 +1117,13 @@ contract Nodes is Permissions, INodes { return validatorNodeIndexes.length; } - function _publicKeyToAddress(bytes32[2] memory pubKey) private pure returns (address nodeAddress) { + function _publicKeyToAddress( + bytes32[2] memory pubKey + ) + private + pure + returns (address nodeAddress) + { bytes32 hash = keccak256(abi.encodePacked(pubKey[0], pubKey[1])); bytes20 addr; for (uint8 i = 12; i < 32; i++) { diff --git a/contracts/PaymasterController.sol b/contracts/PaymasterController.sol new file mode 100644 index 000000000..030d4885f --- /dev/null +++ b/contracts/PaymasterController.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/* + PaymasterController.sol - SKALE Manager + Copyright (C) 2024-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 . +*/ + +pragma solidity 0.8.26; + +import { + AddressUpgradeable +} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; +import { Encoder } from "@skalenetwork/marionette-interfaces/Encoder.sol"; +import { + IMessageProxyForMainnet +} from "@skalenetwork/ima-interfaces/mainnet/IMessageProxyForMainnet.sol"; +import { IMarionette } from "@skalenetwork/marionette-interfaces/IMarionette.sol"; +import { IPaymaster } from "@skalenetwork/paymaster-interfaces/IPaymaster.sol"; +import { + IPaymasterController +} from "@skalenetwork/skale-manager-interfaces/IPaymasterController.sol"; + +import { IsNotContract, RoleRequired } from "./CommonErrors.sol"; +import { Permissions } from "./Permissions.sol"; + + +/** + * @title PaymasterController + * @dev This contract serves to interact with Paymaster contract + * on Europa chain. + * + */ +contract PaymasterController is IPaymasterController, Permissions { + using AddressUpgradeable for address; + using AddressUpgradeable for address payable; + + bytes32 public constant PAYMASTER_SETTER_ROLE = keccak256("PAYMASTER_SETTER_ROLE"); + + IMessageProxyForMainnet public ima; + IMarionette public marionette; + IPaymaster public paymaster; + bytes32 public paymasterChainHash; + + error MessageProxyForMainnetAddressIsNotSet(); + error MarionetteAddressIsNotSet(); + error PaymasterAddressIsNotSet(); + error EuropaChainHashIsNotSet(); + + modifier whenConfigured() { + if (address(ima) == address(0)) { + revert MessageProxyForMainnetAddressIsNotSet(); + } + if (address(marionette) == address(0)) { + revert MarionetteAddressIsNotSet(); + } + if (address(paymaster) == address(0)) { + revert PaymasterAddressIsNotSet(); + } + if (paymasterChainHash == 0) { + revert EuropaChainHashIsNotSet(); + } + _; + } + + modifier onlyPaymasterSetter() { + if (!hasRole(PAYMASTER_SETTER_ROLE, msg.sender)) { + revert RoleRequired(PAYMASTER_SETTER_ROLE); + } + _; + } + + function initialize(address contractManagerAddress) public override initializer { + Permissions.initialize(contractManagerAddress); + _setupRole(PAYMASTER_SETTER_ROLE, msg.sender); + } + + function setImaAddress(address imaAddress) external override onlyPaymasterSetter { + if (!imaAddress.isContract()) { + revert IsNotContract(imaAddress); + } + ima = IMessageProxyForMainnet(imaAddress); + } + + function setMarionetteAddress( + address payable marionetteAddress + ) + external + override + onlyPaymasterSetter + { + if (!marionetteAddress.isContract()) { + revert IsNotContract(marionetteAddress); + } + marionette = IMarionette(marionetteAddress); + } + + function setPaymasterAddress(address paymasterAddress) external override onlyPaymasterSetter { + if (!paymasterAddress.isContract()) { + revert IsNotContract(paymasterAddress); + } + paymaster = IPaymaster(paymasterAddress); + } + + function setPaymasterChainHash(bytes32 chainHash) external override onlyPaymasterSetter { + paymasterChainHash = chainHash; + } + + function addSchain(string calldata name) external override allow("Schains") { + _callPaymaster(abi.encodeWithSelector( + paymaster.addSchain.selector, + name + )); + } + + function removeSchain(bytes32 schainHash) external override allow("Schains") { + _callPaymaster(abi.encodeWithSelector( + paymaster.removeSchain.selector, + schainHash + )); + } + + function addValidator( + uint256 validatorId, + address validatorAddress + ) + external + override + allow("ValidatorService") + { + _callPaymaster(abi.encodeWithSelector( + paymaster.addValidator.selector, + validatorId, + validatorAddress + )); + } + + function setValidatorAddress( + uint256 validatorId, + address validatorAddress + ) + external + override + allow("ValidatorService") + { + _callPaymaster(abi.encodeWithSelector( + paymaster.setValidatorAddress.selector, + validatorId, + validatorAddress + )); + } + + function setNodesAmount( + uint256 validatorId, + uint256 nodesAmount + ) + external + override + allow("Nodes") + { + _callPaymaster(abi.encodeWithSelector( + paymaster.setNodesAmount.selector, + validatorId, + nodesAmount + )); + } + + function _callPaymaster(bytes memory data) private whenConfigured { + ima.postOutgoingMessage( + paymasterChainHash, + address(marionette), + Encoder.encodeFunctionCall( + address(paymaster), + 0, + data + ) + ); + } +} diff --git a/contracts/Permissions.sol b/contracts/Permissions.sol index b6fd25bde..688bc9f01 100644 --- a/contracts/Permissions.sol +++ b/contracts/Permissions.sol @@ -19,13 +19,17 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; +pragma solidity ^0.8.17; -import { AddressUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; +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"; +import { + AccessControlUpgradeableLegacy +} from "./thirdparty/openzeppelin/AccessControlUpgradeableLegacy.sol"; /** @@ -102,7 +106,12 @@ contract Permissions is AccessControlUpgradeableLegacy, IPermissions { * - The caller must be the owner, `contractName1`, `contractName2`, or * `contractName3`. */ - modifier allowThree(string memory contractName1, string memory contractName2, string memory contractName3) { + modifier allowThree( + string memory contractName1, + string memory contractName2, + string memory contractName3 + ) + { require( contractManager.getContract(contractName1) == msg.sender || contractManager.getContract(contractName2) == msg.sender || @@ -123,9 +132,11 @@ contract Permissions is AccessControlUpgradeableLegacy, IPermissions { } function _isAdmin(address account) internal view returns (bool admin) { - address skaleManagerAddress = contractManager.contracts(keccak256(abi.encodePacked("SkaleManager"))); + address skaleManagerAddress = + contractManager.contracts(keccak256(abi.encodePacked("SkaleManager"))); if (skaleManagerAddress != address(0)) { - AccessControlUpgradeableLegacy skaleManager = AccessControlUpgradeableLegacy(skaleManagerAddress); + AccessControlUpgradeableLegacy skaleManager = + AccessControlUpgradeableLegacy(skaleManagerAddress); return skaleManager.hasRole(keccak256("ADMIN_ROLE"), account) || _isOwner(); } else { return _isOwner(); diff --git a/contracts/Pricing.sol b/contracts/Pricing.sol deleted file mode 100644 index 3434a629f..000000000 --- a/contracts/Pricing.sol +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only - -/* - Pricing.sol - SKALE Manager - Copyright (C) 2018-Present SKALE Labs - @author Artem Payvin - @author Vadim Yavorsky - - SKALE Manager is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SKALE Manager is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with SKALE Manager. If not, see . -*/ - -pragma solidity 0.8.17; - -import { IPricing } from "@skalenetwork/skale-manager-interfaces/IPricing.sol"; -import { ISchainsInternal } from "@skalenetwork/skale-manager-interfaces/ISchainsInternal.sol"; -import { INodes } from "@skalenetwork/skale-manager-interfaces/INodes.sol"; - -import { Permissions } from "./Permissions.sol"; -import { ConstantsHolder } from "./ConstantsHolder.sol"; - -/** - * @title Pricing - * @dev Contains pricing operations for SKALE network. - */ -contract Pricing is Permissions, IPricing { - - uint256 public constant INITIAL_PRICE = 5 * 10**6; - - uint256 public price; - uint256 public totalNodes; - uint256 public lastUpdated; - - function initialize(address newContractsAddress) public override initializer { - Permissions.initialize(newContractsAddress); - lastUpdated = block.timestamp; - price = INITIAL_PRICE; - } - - function initNodes() external override { - INodes nodes = INodes(contractManager.getContract("Nodes")); - totalNodes = nodes.getNumberOnlineNodes(); - } - - /** - * @dev Adjust the schain price based on network capacity and demand. - * - * Requirements: - * - * - Cooldown time has exceeded. - */ - function adjustPrice() external override { - ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); - require( - block.timestamp > lastUpdated + constantsHolder.COOLDOWN_TIME(), - "It's not a time to update a price" - ); - checkAllNodes(); - uint256 load = _getTotalLoad(); - uint256 capacity = _getTotalCapacity(); - - bool networkIsOverloaded = load * 100 > constantsHolder.OPTIMAL_LOAD_PERCENTAGE() * capacity; - uint256 loadDiff; - if (networkIsOverloaded) { - loadDiff = load * 100 - constantsHolder.OPTIMAL_LOAD_PERCENTAGE() * capacity; - } else { - loadDiff = constantsHolder.OPTIMAL_LOAD_PERCENTAGE() * capacity - load * 100; - } - - uint256 priceChangeSpeedMultipliedByCapacityAndMinPrice = - constantsHolder.ADJUSTMENT_SPEED() * loadDiff * price; - - uint256 timeSkipped = block.timestamp - lastUpdated; - - uint256 priceChange = priceChangeSpeedMultipliedByCapacityAndMinPrice - * timeSkipped - / constantsHolder.COOLDOWN_TIME() - / capacity - / constantsHolder.MIN_PRICE(); - - if (networkIsOverloaded) { - assert(priceChange > 0); - price = price + priceChange; - } else { - if (priceChange > price) { - price = constantsHolder.MIN_PRICE(); - } else { - price = price - priceChange; - if (price < constantsHolder.MIN_PRICE()) { - price = constantsHolder.MIN_PRICE(); - } - } - } - lastUpdated = block.timestamp; - } - - /** - * @dev Returns the total load percentage. - */ - function getTotalLoadPercentage() external view override returns (uint256 load) { - return _getTotalLoad() * 100 / _getTotalCapacity(); - } - - function checkAllNodes() public override { - INodes nodes = INodes(contractManager.getContract("Nodes")); - uint256 numberOfActiveNodes = nodes.getNumberOnlineNodes(); - - require(totalNodes != numberOfActiveNodes, "No changes to node supply"); - totalNodes = numberOfActiveNodes; - } - - function _getTotalLoad() private view returns (uint256 load) { - ISchainsInternal schainsInternal = ISchainsInternal(contractManager.getContract("SchainsInternal")); - - load = 0; - uint256 numberOfSchains = schainsInternal.numberOfSchains(); - for (uint256 i = 0; i < numberOfSchains; i++) { - bytes32 schain = schainsInternal.schainsAtSystem(i); - uint256 numberOfNodesInSchain = schainsInternal.getNumberOfNodesInGroup(schain); - uint256 part = schainsInternal.getSchainsPartOfNode(schain); - load = load + numberOfNodesInSchain * part; - } - return load; - } - - function _getTotalCapacity() private view returns (uint256 capacity) { - INodes nodes = INodes(contractManager.getContract("Nodes")); - ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); - - return nodes.getNumberOnlineNodes() * constantsHolder.TOTAL_SPACE_ON_NODE(); - } -} diff --git a/contracts/Schains.sol b/contracts/Schains.sol index 8bd3e2764..1f15aff92 100644 --- a/contracts/Schains.sol +++ b/contracts/Schains.sol @@ -19,11 +19,14 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; +pragma solidity 0.8.26; -import { AddressUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; +import { + AddressUpgradeable +} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import { EnumerableSetUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; +import { IConstantsHolder } from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; import { ISchains } from "@skalenetwork/skale-manager-interfaces/ISchains.sol"; import { ISkaleVerifier } from "@skalenetwork/skale-manager-interfaces/ISkaleVerifier.sol"; import { ISkaleDKG } from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; @@ -32,9 +35,10 @@ import { IKeyStorage } from "@skalenetwork/skale-manager-interfaces/IKeyStorage. import { INodeRotation } from "@skalenetwork/skale-manager-interfaces/INodeRotation.sol"; import { IWallets } from "@skalenetwork/skale-manager-interfaces/IWallets.sol"; -import { Permissions } from "./Permissions.sol"; -import { ConstantsHolder } from "./ConstantsHolder.sol"; import { G2Operations } from "./utils/fieldOperations/G2Operations.sol"; +import { NotEnoughFunds, RoleRequired } from "./CommonErrors.sol"; +import { PaymasterController } from "./PaymasterController.sol"; +import { Permissions } from "./Permissions.sol"; /** @@ -62,8 +66,24 @@ contract Schains is Permissions, ISchains { bytes32 public constant SCHAIN_CREATOR_ROLE = keccak256("SCHAIN_CREATOR_ROLE"); + error SchainDoesNotExist(bytes32 schainHash); + error SchainIsCreatedTooEarly(); + error SchainLifetimeIsTooSmall(); + error SenderIsNotTheOwnerOfTheSchain(); + error DkgWasNotFailed(); + error NoFreeNodes(); + error SchainNameIsNotAvailable(string schainName); + error OriginatorIsAContract(address originator); + error OriginatorIsNotProvided(); + error NodeDoesNotContainGivenSchain(uint256 node, bytes32 schain); + error OptionIsAlreadySet(string optionName); + error OptionRemovingError(bytes32 optionHash); + error OptionIsNotSet(bytes32 schainHash, bytes32 optionHash); + modifier schainExists(ISchainsInternal schainsInternal, bytes32 schainHash) { - require(schainsInternal.isSchainExist(schainHash), "The schain does not exist"); + if(!schainsInternal.isSchainExist(schainHash)) { + revert SchainDoesNotExist(schainHash); + } _; } @@ -82,19 +102,28 @@ contract Schains is Permissions, ISchains { * - There is sufficient deposit to create type of schain. * - If from is a smart contract originator must be specified */ - function addSchain(address from, uint256 deposit, bytes calldata data) external override allow("SkaleManager") { + function addSchain( + address from, + uint256 deposit, + bytes calldata data + ) + external + override + allow("SkaleManager") + { SchainParameters memory schainParameters = abi.decode(data, (SchainParameters)); - ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getConstantsHolder()); + IConstantsHolder constantsHolder = IConstantsHolder(contractManager.getConstantsHolder()); uint256 schainCreationTimeStamp = constantsHolder.schainCreationTimeStamp(); uint256 minSchainLifetime = constantsHolder.minimalSchainLifetime(); - require(block.timestamp >= schainCreationTimeStamp, "It is not a time for creating Schain"); - require( - schainParameters.lifetime >= minSchainLifetime, - "Minimal schain lifetime should be satisfied" - ); - require( - getSchainPrice(schainParameters.typeOfSchain, schainParameters.lifetime) <= deposit, - "Not enough money to create Schain"); + if(block.timestamp < schainCreationTimeStamp) { + revert SchainIsCreatedTooEarly(); + } + if (schainParameters.lifetime < minSchainLifetime) { + revert SchainLifetimeIsTooSmall(); + } + if (deposit < getSchainPrice(schainParameters.typeOfSchain, schainParameters.lifetime)) { + revert NotEnoughFunds(); + } _addSchain(from, deposit, schainParameters); } @@ -122,7 +151,9 @@ contract Schains is Permissions, ISchains { payable override { - require(hasRole(SCHAIN_CREATOR_ROLE, msg.sender), "Sender is not authorized to create schain"); + if (!hasRole(SCHAIN_CREATOR_ROLE, msg.sender)) { + revert RoleRequired(SCHAIN_CREATOR_ROLE); + } SchainParameters memory schainParameters = SchainParameters({ lifetime: lifetime, @@ -142,7 +173,9 @@ contract Schains is Permissions, ISchains { _addSchain(_schainOwner, 0, schainParameters); bytes32 schainHash = keccak256(abi.encodePacked(name)); - IWallets(payable(contractManager.getContract("Wallets"))).rechargeSchainWallet{value: msg.value}(schainHash); + IWallets( + payable(contractManager.getContract("Wallets")) + ).rechargeSchainWallet{value: msg.value}(schainHash); } /** @@ -155,13 +188,20 @@ contract Schains is Permissions, ISchains { * * - Executed by schain owner. */ - function deleteSchain(address from, string calldata name) external override allow("SkaleManager") { - ISchainsInternal schainsInternal = ISchainsInternal(contractManager.getContract("SchainsInternal")); + function deleteSchain( + address from, + string calldata name + ) + external + override + allow("SkaleManager") + { + ISchainsInternal schainsInternal = + ISchainsInternal(contractManager.getContract("SchainsInternal")); bytes32 schainHash = keccak256(abi.encodePacked(name)); - require( - schainsInternal.isOwnerAddress(from, schainHash), - "Message sender is not the owner of the Schain" - ); + if (!schainsInternal.isOwnerAddress(from, schainHash)) { + revert SenderIsNotTheOwnerOfTheSchain(); + } _deleteSchain(name, schainsInternal); } @@ -196,10 +236,14 @@ contract Schains is Permissions, ISchains { INodeRotation nodeRotation = INodeRotation(contractManager.getContract("NodeRotation")); bytes32 schainHash = keccak256(abi.encodePacked(name)); ISkaleDKG skaleDKG = ISkaleDKG(contractManager.getContract("SkaleDKG")); - require(!skaleDKG.isLastDKGSuccessful(schainHash), "DKG success"); + if (skaleDKG.isLastDKGSuccessful(schainHash)) { + revert DkgWasNotFailed(); + } ISchainsInternal schainsInternal = ISchainsInternal( contractManager.getContract("SchainsInternal")); - require(schainsInternal.isAnyFreeNode(schainHash), "No free Nodes for new group formation"); + if (!schainsInternal.isAnyFreeNode(schainHash)) { + revert NoFreeNodes(); + } uint256 newNodeIndex = nodeRotation.rotateNode( skaleDKG.pendingToBeReplaced(schainHash), schainHash, @@ -234,7 +278,9 @@ contract Schains is Permissions, ISchains { bytes32 schainHash = keccak256(abi.encodePacked(schainName)); if ( INodeRotation(contractManager.getContract("NodeRotation")).isNewNodeFound(schainHash) && - INodeRotation(contractManager.getContract("NodeRotation")).isRotationInProgress(schainHash) && + INodeRotation( + contractManager.getContract("NodeRotation") + ).isRotationInProgress(schainHash) && ISkaleDKG(contractManager.getContract("SkaleDKG")).isLastDKGSuccessful(schainHash) ) { publicKey = IKeyStorage( @@ -277,7 +323,14 @@ contract Schains is Permissions, ISchains { return _getOption(schainHash, optionHash, schainsInternal); } - function getOptions(bytes32 schainHash) external view override returns (SchainOption[] memory option) { + function getOptions( + bytes32 schainHash + ) + external + view + override + returns (SchainOption[] memory option) + { SchainOption[] memory options = new SchainOption[](_optionsIndex[schainHash].length()); for (uint256 i = 0; i < options.length; ++i) { options[i] = _options[schainHash][_optionsIndex[schainHash].at(i)]; @@ -288,9 +341,18 @@ contract Schains is Permissions, ISchains { /** * @dev Returns the current price in SKL tokens for given Schain type and lifetime. */ - function getSchainPrice(uint256 typeOfSchain, uint256 lifetime) public view override returns (uint256 price) { - ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getConstantsHolder()); - ISchainsInternal schainsInternal = ISchainsInternal(contractManager.getContract("SchainsInternal")); + function getSchainPrice( + uint256 typeOfSchain, + uint256 lifetime + ) + public + view + override + returns (uint256 price) + { + IConstantsHolder constantsHolder = IConstantsHolder(contractManager.getConstantsHolder()); + ISchainsInternal schainsInternal = + ISchainsInternal(contractManager.getContract("SchainsInternal")); uint256 nodeDeposit = constantsHolder.NODE_DEPOSIT(); uint256 numberOfNodes; uint8 divisor; @@ -327,7 +389,9 @@ contract Schains is Permissions, ISchains { ) private { - require(schainsInternal.isSchainNameAvailable(name), "Schain name is not available"); + if (!schainsInternal.isSchainNameAvailable(name)) { + revert SchainNameIsNotAvailable(name); + } bytes32 schainHash = keccak256(abi.encodePacked(name)); for (uint256 i = 0; i < options.length; ++i) { @@ -358,7 +422,11 @@ contract Schains is Permissions, ISchains { ) private { - uint256[] memory nodesInGroup = schainsInternal.createGroupForSchain(schainHash, numberOfNodes, partOfNode); + uint256[] memory nodesInGroup = schainsInternal.createGroupForSchain( + schainHash, + numberOfNodes, + partOfNode + ); ISkaleDKG(contractManager.getContract("SkaleDKG")).openChannel(schainHash); emit SchainNodes( @@ -376,17 +444,18 @@ contract Schains is Permissions, ISchains { * * - Schain type must be valid. */ - function _addSchain(address from, uint256 deposit, SchainParameters memory schainParameters) private { - ISchainsInternal schainsInternal = ISchainsInternal(contractManager.getContract("SchainsInternal")); - - require(!schainParameters.originator.isContract(), "Originator address must be not a contract"); - if (from.isContract()) { - require(schainParameters.originator != address(0), "Originator address is not provided"); - } else { - schainParameters.originator = address(0); - } + function _addSchain( + address from, + uint256 deposit, + SchainParameters memory schainParameters + ) + private + { + _checkOriginator(from, schainParameters); //initialize Schain + ISchainsInternal schainsInternal = + ISchainsInternal(contractManager.getContract("SchainsInternal")); _initializeSchainInSchainsInternal({ name: schainParameters.name, from: from, @@ -420,13 +489,16 @@ contract Schains is Permissions, ISchains { nonce: schainParameters.nonce, schainHash: keccak256(abi.encodePacked(schainParameters.name)) }); + + PaymasterController paymasterController = + PaymasterController(contractManager.getContract("PaymasterController")); + paymasterController.addSchain(schainParameters.name); } function _deleteSchain(string calldata name, ISchainsInternal schainsInternal) private { INodeRotation nodeRotation = INodeRotation(contractManager.getContract("NodeRotation")); bytes32 schainHash = keccak256(abi.encodePacked(name)); - require(schainsInternal.isSchainExist(schainHash), "Schain does not exist"); _deleteOptions(schainHash, schainsInternal); @@ -435,10 +507,9 @@ contract Schains is Permissions, ISchains { if (schainsInternal.checkHoleForSchain(schainHash, i)) { continue; } - require( - schainsInternal.checkSchainOnNode(nodesInGroup[i], schainHash), - "Some Node does not contain given Schain" - ); + if (!schainsInternal.checkSchainOnNode(nodesInGroup[i], schainHash)) { + revert NodeDoesNotContainGivenSchain(nodesInGroup[i], schainHash); + } schainsInternal.removeNodeFromSchain(nodesInGroup[i], schainHash); } schainsInternal.removeAllNodesFromSchainExceptions(schainHash); @@ -451,6 +522,10 @@ contract Schains is Permissions, ISchains { payable(contractManager.getContract("Wallets")) ).withdrawFundsFromSchainWallet(payable(from), schainHash); emit SchainDeleted(from, name, schainHash); + + PaymasterController paymasterController = + PaymasterController(contractManager.getContract("PaymasterController")); + paymasterController.removeSchain(schainHash); } function _setOption( @@ -461,7 +536,9 @@ contract Schains is Permissions, ISchains { { bytes32 optionHash = keccak256(abi.encodePacked(option.name)); _options[schainHash][optionHash] = option; - require(_optionsIndex[schainHash].add(optionHash), "The option has been set already"); + if (!_optionsIndex[schainHash].add(optionHash)) { + revert OptionIsAlreadySet(option.name); + } } function _deleteOptions( @@ -474,7 +551,9 @@ contract Schains is Permissions, ISchains { while (_optionsIndex[schainHash].length() > 0) { bytes32 optionHash = _optionsIndex[schainHash].at(0); delete _options[schainHash][optionHash]; - require(_optionsIndex[schainHash].remove(optionHash), "Removing error"); + if (!_optionsIndex[schainHash].remove(optionHash)) { + revert OptionRemovingError(optionHash); + } } } @@ -488,7 +567,22 @@ contract Schains is Permissions, ISchains { schainExists(schainsInternal, schainHash) returns (bytes memory option) { - require(_optionsIndex[schainHash].contains(optionHash), "Option is not set"); + if (!_optionsIndex[schainHash].contains(optionHash)) { + revert OptionIsNotSet(schainHash, optionHash); + } return _options[schainHash][optionHash].value; } + + function _checkOriginator(address from, SchainParameters memory schainParameters) private view { + if (schainParameters.originator.isContract()) { + revert OriginatorIsAContract(schainParameters.originator); + } + if (from.isContract()) { + if (schainParameters.originator == address(0)) { + revert OriginatorIsNotProvided(); + } + } else { + schainParameters.originator = address(0); + } + } } diff --git a/contracts/SchainsInternal.sol b/contracts/SchainsInternal.sol index 1e609bee7..9a0c62d0f 100644 --- a/contracts/SchainsInternal.sol +++ b/contracts/SchainsInternal.sol @@ -91,7 +91,10 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { bytes32 public constant GENERATION_MANAGER_ROLE = keccak256("GENERATION_MANAGER_ROLE"); modifier onlySchainTypeManager() { - require(hasRole(SCHAIN_TYPE_MANAGER_ROLE, msg.sender), "SCHAIN_TYPE_MANAGER_ROLE is required"); + require( + hasRole(SCHAIN_TYPE_MANAGER_ROLE, msg.sender), + "SCHAIN_TYPE_MANAGER_ROLE is required" + ); _; } @@ -101,7 +104,10 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { } modifier onlyGenerationManager() { - require(hasRole(GENERATION_MANAGER_ROLE, msg.sender), "GENERATION_MANAGER_ROLE is required"); + require( + hasRole(GENERATION_MANAGER_ROLE, msg.sender), + "GENERATION_MANAGER_ROLE is required" + ); _; } @@ -173,7 +179,8 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { schainExists(schainHash) returns (uint256[] memory group) { - ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); + ConstantsHolder constantsHolder = + ConstantsHolder(contractManager.getContract("ConstantsHolder")); schains[schainHash].partOfNode = partOfNode; if (partOfNode > 0) { sumOfSchainsResources = sumOfSchainsResources + @@ -270,7 +277,8 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { schainsGroups[schainHash].pop(); } else { delete schainsGroups[schainHash][indexOfNode]; - if (holesForSchains[schainHash].length > 0 && holesForSchains[schainHash][0] > indexOfNode) { + if (holesForSchains[schainHash].length > 0 + && holesForSchains[schainHash][0] > indexOfNode) { uint256 hole = holesForSchains[schainHash][0]; holesForSchains[schainHash][0] = indexOfNode; holesForSchains[schainHash].push(hole); @@ -282,7 +290,10 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { removeSchainForNode(nodeIndex, placeOfSchainOnNode[schainHash][nodeIndex] - 1); delete placeOfSchainOnNode[schainHash][nodeIndex]; INodes nodes = INodes(contractManager.getContract("Nodes")); - require(_removeAddressFromSchain(schainHash, nodes.getNodeAddress(nodeIndex)), "Incorrect node address"); + require( + _removeAddressFromSchain(schainHash, nodes.getNodeAddress(nodeIndex)), + "Incorrect node address" + ); nodes.addSpaceToNode(nodeIndex, schains[schainHash].partOfNode); } @@ -294,7 +305,14 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { * - Message sender is Schains smart contract * - Schain must exist */ - function deleteGroup(bytes32 schainHash) external override allow("Schains") schainExists(schainHash) { + function deleteGroup( + bytes32 schainHash + ) + external + override + allow("Schains") + schainExists(schainHash) + { // delete channel ISkaleDKG skaleDKG = ISkaleDKG(contractManager.getContract("SkaleDKG")); delete schainsGroups[schainHash]; @@ -371,14 +389,28 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { * - Message sender is Schains smart contract * - Schain must exist */ - function removeHolesForSchain(bytes32 schainHash) external override allow("Schains") schainExists(schainHash) { + function removeHolesForSchain( + bytes32 schainHash + ) + external + override + allow("Schains") + schainExists(schainHash) + { delete holesForSchains[schainHash]; } /** * @dev Allows Admin to add schain type */ - function addSchainType(uint8 partOfNode, uint256 numberOfNodes) external override onlySchainTypeManager { + function addSchainType( + uint8 partOfNode, + uint256 numberOfNodes + ) + external + override + onlySchainTypeManager + { require(_keysOfSchainTypes.add(numberOfSchainTypes + 1), "Schain type is already added"); schainTypes[numberOfSchainTypes + 1].partOfNode = partOfNode; schainTypes[numberOfSchainTypes + 1].numberOfNodes = numberOfNodes; @@ -399,11 +431,23 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { /** * @dev Allows Admin to set number of schain types */ - function setNumberOfSchainTypes(uint256 newNumberOfSchainTypes) external override onlySchainTypeManager { + function setNumberOfSchainTypes( + uint256 newNumberOfSchainTypes + ) + external + override + onlySchainTypeManager + { numberOfSchainTypes = newNumberOfSchainTypes; } - function removeNodeFromAllExceptionSchains(uint256 nodeIndex) external override allow("SkaleManager") { + function removeNodeFromAllExceptionSchains( + uint256 nodeIndex + ) + external + override + allow("SkaleManager") + { uint256 len = _nodeToLockedSchains[nodeIndex].length; for (uint256 i = len; i > 0; i--) { removeNodeFromExceptions(_nodeToLockedSchains[nodeIndex][i - 1], nodeIndex); @@ -413,7 +457,13 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { /** * @dev Clear list of nodes that can't be chosen to schain with id {schainHash} */ - function removeAllNodesFromSchainExceptions(bytes32 schainHash) external override allow("Schains") { + function removeAllNodesFromSchainExceptions( + bytes32 schainHash + ) + external + override + allow("Schains") + { uint256 nodesAmount = _schainToExceptionNodes[schainHash].length; for (uint256 i = nodesAmount; i > 0; --i) { removeNodeFromExceptions(schainHash, _schainToExceptionNodes[schainHash][i - 1]); @@ -532,14 +582,28 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { /** * @dev Returns hashes of schain names by schain owner. */ - function getSchainHashesByAddress(address from) external view override returns (bytes32[] memory schainsByOwner) { + function getSchainHashesByAddress( + address from + ) + external + view + override + returns (bytes32[] memory schainsByOwner) + { return schainIndexes[from]; } /** * @dev Returns hashes of schain names running on a node. */ - function getSchainHashesForNode(uint256 nodeIndex) external view override returns (bytes32[] memory nodeSchains) { + function getSchainHashesForNode( + uint256 nodeIndex + ) + external + view + override + returns (bytes32[] memory nodeSchains) + { return schainsForNodes[nodeIndex]; } @@ -584,7 +648,14 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { * @dev Checks whether schain name is available. * TODO Need to delete - copy of web3.utils.soliditySha3 */ - function isSchainNameAvailable(string calldata name) external view override returns (bool available) { + function isSchainNameAvailable( + string calldata name + ) + external + view + override + returns (bool available) + { bytes32 schainHash = keccak256(abi.encodePacked(name)); return schains[schainHash].owner == address(0) && !usedSchainNames[schainHash] && @@ -599,7 +670,15 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { * * - Schain must exist */ - function isTimeExpired(bytes32 schainHash) external view override schainExists(schainHash) returns (bool expired) { + function isTimeExpired( + bytes32 schainHash + ) + external + view + override + schainExists(schainHash) + returns (bool expired) + { return uint(schains[schainHash].startDate) + schains[schainHash].lifetime < block.timestamp; } @@ -654,7 +733,14 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { /** * @dev Returns active schains of a node. */ - function getActiveSchains(uint256 nodeIndex) external view override returns (bytes32[] memory activeSchains) { + function getActiveSchains( + uint256 nodeIndex + ) + external + view + override + returns (bytes32[] memory activeSchains) + { uint256 activeAmount = schainsForNodes[nodeIndex].length - holesForNodes[nodeIndex].length; uint256 cursor = 0; @@ -754,7 +840,15 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { * * - Schain must exist */ - function isAnyFreeNode(bytes32 schainHash) external view override schainExists(schainHash) returns (bool free) { + function isAnyFreeNode( + bytes32 schainHash + ) + external + view + override + schainExists(schainHash) + returns (bool free) + { // TODO: // Move this function to Nodes? INodes nodes = INodes(contractManager.getContract("Nodes")); @@ -831,7 +925,14 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { return placeOfSchainOnNode[schainHash][nodeIndex] != 0; } - function getSchainType(uint256 typeOfSchain) external view override returns(uint8 partOfNode, uint256 schainType) { + function getSchainType( + uint256 typeOfSchain + ) + external + view + override + returns(uint8 partOfNode, uint256 schainType) + { require(_keysOfSchainTypes.contains(typeOfSchain), "Invalid type of schain"); return (schainTypes[typeOfSchain].partOfNode, schainTypes[typeOfSchain].numberOfNodes); } @@ -882,7 +983,10 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { placeOfSchainOnNode[schainHash][nodeIndex] = lastHoleOfNode + 1; holesForNodes[nodeIndex].pop(); } - require(_addAddressToSchain(schainHash, nodes.getNodeAddress(nodeIndex)), "Node address already exist"); + require( + _addAddressToSchain(schainHash, nodes.getNodeAddress(nodeIndex)), + "Node address already exist" + ); } /** @@ -928,7 +1032,8 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { for (uint256 i = len; i > 0; i--) { if (_nodeToLockedSchains[nodeIndex][i - 1] == schainHash) { if (i != len) { - _nodeToLockedSchains[nodeIndex][i - 1] = _nodeToLockedSchains[nodeIndex][len - 1]; + _nodeToLockedSchains[nodeIndex][i - 1] = + _nodeToLockedSchains[nodeIndex][len - 1]; } _nodeToLockedSchains[nodeIndex].pop(); break; @@ -938,7 +1043,8 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { for (uint256 i = len; i > 0; i--) { if (_schainToExceptionNodes[schainHash][i - 1] == nodeIndex) { if (i != len) { - _schainToExceptionNodes[schainHash][i - 1] = _schainToExceptionNodes[schainHash][len - 1]; + _schainToExceptionNodes[schainHash][i - 1] = + _schainToExceptionNodes[schainHash][len - 1]; } _schainToExceptionNodes[schainHash].pop(); break; @@ -953,7 +1059,14 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { return bytes(schains[schainHash].name).length != 0; } - function _addAddressToSchain(bytes32 schainHash, address nodeAddress) internal virtual returns (bool successful) { + function _addAddressToSchain( + bytes32 schainHash, + address nodeAddress + ) + internal + virtual + returns (bool successful) + { return _nodeAddressInSchain[schainHash].add(nodeAddress); } @@ -987,12 +1100,21 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { /** * @dev Generates schain group using a pseudo-random generator. */ - function _generateGroup(bytes32 schainHash, uint256 numberOfNodes) private returns (uint256[] memory nodesInGroup) { + function _generateGroup( + bytes32 schainHash, + uint256 numberOfNodes + ) + private + returns (uint256[] memory nodesInGroup) + { INodes nodes = INodes(contractManager.getContract("Nodes")); uint8 space = schains[schainHash].partOfNode; nodesInGroup = new uint256[](numberOfNodes); - require(nodes.countNodesWithFreeSpace(space) >= nodesInGroup.length, "Not enough nodes to create Schain"); + require( + nodes.countNodesWithFreeSpace(space) >= nodesInGroup.length, + "Not enough nodes to create Schain" + ); IRandom.RandomGenerator memory randomGenerator = Random.createFromEntropy( abi.encodePacked(uint256(blockhash(block.number - 1)), schainHash) ); @@ -1001,7 +1123,11 @@ contract SchainsInternal is Permissions, IPruningSchainsInternal { nodesInGroup[i] = node; _setException(schainHash, node); addSchainForNode(nodes, node, schainHash); + // The function makeNodeInvisible does not do external calls + //slither-disable-next-line reentrancy-benign nodes.makeNodeInvisible(node); + // The function removeSpaceFromNode does not do external calls + //slither-disable-next-line reentrancy-benign require(nodes.removeSpaceFromNode(node, space), "Could not remove space from Node"); } // set generated group diff --git a/contracts/SkaleDKG.sol b/contracts/SkaleDKG.sol index 38f28b1da..3d68ba1b5 100644 --- a/contracts/SkaleDKG.sol +++ b/contracts/SkaleDKG.sol @@ -185,7 +185,8 @@ contract SkaleDKG is Permissions, ISkaleDKG { schainHash, Context({ isDebt: true, - delta: ConstantsHolder(contractManager.getConstantsHolder()).COMPLAINT_BAD_DATA_DELTA(), + delta: ConstantsHolder(contractManager.getConstantsHolder()) + .COMPLAINT_BAD_DATA_DELTA(), dkgFunction: DkgFunction.ComplaintBadData })) correctGroupWithoutRevert(schainHash) @@ -326,7 +327,14 @@ contract SkaleDKG is Permissions, ISkaleDKG { delete pendingToBeReplaced[schainHash]; } - function finalizeSlashing(bytes32 schainHash, uint256 badNode) external override allow("SkaleDKG") { + function finalizeSlashing( + bytes32 schainHash, + uint256 badNode + ) + external + override + allow("SkaleDKG") + { INodeRotation nodeRotation = INodeRotation(contractManager.getContract("NodeRotation")); ISchainsInternal schainsInternal = ISchainsInternal( contractManager.getContract("SchainsInternal") @@ -353,23 +361,58 @@ contract SkaleDKG is Permissions, ISkaleDKG { ); } - function getChannelStartedTime(bytes32 schainHash) external view override returns (uint256 timestamp) { + function getChannelStartedTime( + bytes32 schainHash + ) + external + view + override + returns (uint256 timestamp) + { return channels[schainHash].startedBlockTimestamp; } - function getChannelStartedBlock(bytes32 schainHash) external view override returns (uint256 blockNumber) { + function getChannelStartedBlock( + bytes32 schainHash + ) + external + view + override + returns (uint256 blockNumber) + { return channels[schainHash].startedBlock; } - function getNumberOfBroadcasted(bytes32 schainHash) external view override returns (uint256 amount) { + function getNumberOfBroadcasted( + bytes32 schainHash + ) + external + view + override + returns (uint256 amount) + { return dkgProcess[schainHash].numberOfBroadcasted; } - function getNumberOfCompleted(bytes32 schainHash) external view override returns (uint256 amount) { + function getNumberOfCompleted( + bytes32 schainHash + ) + external + view + override + returns (uint256 amount) + { return dkgProcess[schainHash].numberOfCompleted; } - function getTimeOfLastSuccessfulDKG(bytes32 schainHash) external view override returns (uint256 timestamp) { + function getTimeOfLastSuccessfulDKG( + bytes32 schainHash + ) + external + view + override + returns (uint256 timestamp) + { return lastSuccessfulDKG[schainHash]; } @@ -384,11 +427,25 @@ contract SkaleDKG is Permissions, ISkaleDKG { return (complaints[schainHash].fromNodeToComplaint, complaints[schainHash].nodeToComplaint); } - function getComplaintStartedTime(bytes32 schainHash) external view override returns (uint256 timestamp) { + function getComplaintStartedTime( + bytes32 schainHash + ) + external + view + override + returns (uint256 timestamp) + { return complaints[schainHash].startComplaintBlockTimestamp; } - function getAlrightStartedTime(bytes32 schainHash) external view override returns (uint256 timestamp) { + function getAlrightStartedTime( + bytes32 schainHash + ) + external + view + override + returns (uint256 timestamp) + { return startAlrightTimestamp[schainHash]; } @@ -399,19 +456,35 @@ contract SkaleDKG is Permissions, ISkaleDKG { return channels[schainHash].active; } - function isLastDKGSuccessful(bytes32 schainHash) external view override returns (bool successful) { + function isLastDKGSuccessful( + bytes32 schainHash + ) + external + view + override + returns (bool successful) + { return channels[schainHash].startedBlockTimestamp <= lastSuccessfulDKG[schainHash]; } /** * @dev Checks whether broadcast is possible. */ - function isBroadcastPossible(bytes32 schainHash, uint256 nodeIndex) external view override returns (bool possible) { + function isBroadcastPossible( + bytes32 schainHash, + uint256 nodeIndex + ) + external + view + override + returns (bool possible) + { (uint256 index, bool check) = checkAndReturnIndexInGroup(schainHash, nodeIndex, false); return channels[schainHash].active && check && _isNodeOwnedByMessageSender(nodeIndex, msg.sender) && - channels[schainHash].startedBlockTimestamp + _getComplaintTimeLimit() > block.timestamp && + channels[schainHash].startedBlockTimestamp + _getComplaintTimeLimit() + > block.timestamp && !dkgProcess[schainHash].broadcasted[index]; } @@ -428,8 +501,16 @@ contract SkaleDKG is Permissions, ISkaleDKG { override returns (bool possible) { - (uint256 indexFrom, bool checkFrom) = checkAndReturnIndexInGroup(schainHash, fromNodeIndex, false); - (uint256 indexTo, bool checkTo) = checkAndReturnIndexInGroup(schainHash, toNodeIndex, false); + (uint256 indexFrom, bool checkFrom) = checkAndReturnIndexInGroup( + schainHash, + fromNodeIndex, + false + ); + (uint256 indexTo, bool checkTo) = checkAndReturnIndexInGroup( + schainHash, + toNodeIndex, + false + ); if (!checkFrom || !checkTo) return false; bool complaintSending = ( @@ -439,13 +520,15 @@ contract SkaleDKG is Permissions, ISkaleDKG { ) || ( dkgProcess[schainHash].broadcasted[indexTo] && - complaints[schainHash].startComplaintBlockTimestamp + _getComplaintTimeLimit() <= block.timestamp && + complaints[schainHash].startComplaintBlockTimestamp + _getComplaintTimeLimit() + <= block.timestamp && complaints[schainHash].nodeToComplaint == toNodeIndex ) || ( !dkgProcess[schainHash].broadcasted[indexTo] && complaints[schainHash].nodeToComplaint == type(uint256).max && - channels[schainHash].startedBlockTimestamp + _getComplaintTimeLimit() <= block.timestamp + channels[schainHash].startedBlockTimestamp + _getComplaintTimeLimit() + <= block.timestamp ) || ( complaints[schainHash].nodeToComplaint == type(uint256).max && @@ -463,7 +546,15 @@ contract SkaleDKG is Permissions, ISkaleDKG { /** * @dev Checks whether sending Alright response is possible. */ - function isAlrightPossible(bytes32 schainHash, uint256 nodeIndex) external view override returns (bool possible) { + function isAlrightPossible( + bytes32 schainHash, + uint256 nodeIndex + ) + external + view + override + returns (bool possible) + { (uint256 index, bool check) = checkAndReturnIndexInGroup(schainHash, nodeIndex, false); return channels[schainHash].active && check && @@ -492,20 +583,30 @@ contract SkaleDKG is Permissions, ISkaleDKG { check && _isNodeOwnedByMessageSender(nodeIndex, msg.sender) && complaints[schainHash].nodeToComplaint == nodeIndex && - complaints[schainHash].startComplaintBlockTimestamp + _getComplaintTimeLimit() > block.timestamp && + complaints[schainHash].startComplaintBlockTimestamp + _getComplaintTimeLimit() + > block.timestamp && !complaints[schainHash].isResponse; } /** * @dev Checks whether sending a response is possible. */ - function isResponsePossible(bytes32 schainHash, uint256 nodeIndex) external view override returns (bool possible) { + function isResponsePossible( + bytes32 schainHash, + uint256 nodeIndex + ) + external + view + override + returns (bool possible) + { (, bool check) = checkAndReturnIndexInGroup(schainHash, nodeIndex, false); return channels[schainHash].active && check && _isNodeOwnedByMessageSender(nodeIndex, msg.sender) && complaints[schainHash].nodeToComplaint == nodeIndex && - complaints[schainHash].startComplaintBlockTimestamp + _getComplaintTimeLimit() > block.timestamp && + complaints[schainHash].startComplaintBlockTimestamp + _getComplaintTimeLimit() + > block.timestamp && complaints[schainHash].isResponse; } @@ -525,7 +626,15 @@ contract SkaleDKG is Permissions, ISkaleDKG { /** * @dev Checks whether all data has been received by node. */ - function isAllDataReceived(bytes32 schainHash, uint256 nodeIndex) external view override returns (bool received) { + function isAllDataReceived( + bytes32 schainHash, + uint256 nodeIndex + ) + external + view + override + returns (bool received) + { (uint256 index, bool check) = checkAndReturnIndexInGroup(schainHash, nodeIndex, false); return check && dkgProcess[schainHash].completed[index]; } @@ -541,7 +650,11 @@ contract SkaleDKG is Permissions, ISkaleDKG { { bytes memory data; for (uint256 i = 0; i < secretKeyContribution.length; i++) { - data = abi.encodePacked(data, secretKeyContribution[i].publicKey, secretKeyContribution[i].share); + data = abi.encodePacked( + data, + secretKeyContribution[i].publicKey, + secretKeyContribution[i].share + ); } for (uint256 i = 0; i < verificationVector.length; i++) { // Named arguments cannot be used for functions that take arbitrary parameters @@ -575,32 +688,60 @@ contract SkaleDKG is Permissions, ISkaleDKG { return (index, index < channels[schainHash].n); } - function isEveryoneBroadcasted(bytes32 schainHash) public view override returns (bool broadcasted) { + function isEveryoneBroadcasted( + bytes32 schainHash + ) + public + view + override + returns (bool broadcasted) + { return channels[schainHash].n == dkgProcess[schainHash].numberOfBroadcasted; } - function _refundGasBySchain(bytes32 schainHash, uint256 gasTotal, Context memory context) private { + function _refundGasBySchain( + bytes32 schainHash, + uint256 gasTotal, + Context memory context + ) + private + { IWallets wallets = IWallets(payable(contractManager.getContract("Wallets"))); bool isLastNode = channels[schainHash].n == dkgProcess[schainHash].numberOfCompleted; if (context.dkgFunction == DkgFunction.Alright && isLastNode) { wallets.refundGasBySchain( - schainHash, payable(msg.sender), gasTotal - gasleft() + context.delta - 74800, context.isDebt + schainHash, + payable(msg.sender), + gasTotal - gasleft() + context.delta - 74800, + context.isDebt ); } else if (context.dkgFunction == DkgFunction.Complaint && gasTotal - gasleft() > 14e5) { wallets.refundGasBySchain( - schainHash, payable(msg.sender), gasTotal - gasleft() + context.delta - 341979, context.isDebt + schainHash, + payable(msg.sender), + gasTotal - gasleft() + context.delta - 341979, + context.isDebt ); } else if (context.dkgFunction == DkgFunction.Complaint && gasTotal - gasleft() > 7e5) { wallets.refundGasBySchain( - schainHash, payable(msg.sender), gasTotal - gasleft() + context.delta - 152214, context.isDebt + schainHash, + payable(msg.sender), + gasTotal - gasleft() + context.delta - 152214, + context.isDebt ); } else if (context.dkgFunction == DkgFunction.Response){ wallets.refundGasBySchain( - schainHash, payable(msg.sender), gasTotal - gasleft() + context.delta, context.isDebt + schainHash, + payable(msg.sender), + gasTotal - gasleft() + context.delta, + context.isDebt ); } else { wallets.refundGasBySchain( - schainHash, payable(msg.sender), gasTotal - gasleft() + context.delta, context.isDebt + schainHash, + payable(msg.sender), + gasTotal - gasleft() + context.delta, + context.isDebt ); } } @@ -637,12 +778,22 @@ contract SkaleDKG is Permissions, ISkaleDKG { emit ChannelOpened(schainHash); } - function _isNodeOwnedByMessageSender(uint256 nodeIndex, address from) private view returns (bool owned) { + function _isNodeOwnedByMessageSender( + uint256 nodeIndex, + address from + ) + private + view + returns (bool owned) + { return INodes(contractManager.getContract("Nodes")).isNodeExist(from, nodeIndex); } function _checkMsgSenderIsNodeOwner(uint256 nodeIndex) private view { - require(_isNodeOwnedByMessageSender(nodeIndex, msg.sender), "Node does not exist for message sender"); + require( + _isNodeOwnedByMessageSender(nodeIndex, msg.sender), + "Node does not exist for message sender" + ); } function _getComplaintTimeLimit() private view returns (uint256 timeLimit) { diff --git a/contracts/SkaleManager.sol b/contracts/SkaleManager.sol index 4406c13a1..0bbf5c605 100644 --- a/contracts/SkaleManager.sol +++ b/contracts/SkaleManager.sol @@ -28,7 +28,9 @@ import { IERC777Recipient } from "@openzeppelin/contracts/token/ERC777/IERC777Re import { ISkaleManager } from "@skalenetwork/skale-manager-interfaces/ISkaleManager.sol"; import { IMintableToken } from "@skalenetwork/skale-manager-interfaces/IMintableToken.sol"; import { IDistributor } from "@skalenetwork/skale-manager-interfaces/delegation/IDistributor.sol"; -import { IValidatorService } from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; +import { + IValidatorService +} from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; import { IBountyV2 } from "@skalenetwork/skale-manager-interfaces/IBountyV2.sol"; import { IConstantsHolder } from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; import { INodeRotation } from "@skalenetwork/skale-manager-interfaces/INodeRotation.sol"; @@ -62,7 +64,11 @@ contract SkaleManager is IERC777Recipient, ISkaleManager, Permissions { function initialize(address newContractsAddress) public override initializer { Permissions.initialize(newContractsAddress); _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); - _erc1820.setInterfaceImplementer(address(this), _TOKENS_RECIPIENT_INTERFACE_HASH, address(this)); + _erc1820.setInterfaceImplementer( + address(this), + _TOKENS_RECIPIENT_INTERFACE_HASH, + address(this) + ); } function tokensReceived( @@ -115,7 +121,8 @@ contract SkaleManager is IERC777Recipient, ISkaleManager, Permissions { function nodeExit(uint256 nodeIndex) external override { uint256 gasLimit = _getGasLimit(); - IValidatorService validatorService = IValidatorService(contractManager.getContract("ValidatorService")); + IValidatorService validatorService = + IValidatorService(contractManager.getContract("ValidatorService")); INodeRotation nodeRotation = INodeRotation(contractManager.getContract("NodeRotation")); INodes nodes = INodes(contractManager.getContract("Nodes")); uint256 validatorId = nodes.getValidatorId(nodeIndex); @@ -135,7 +142,8 @@ contract SkaleManager is IERC777Recipient, ISkaleManager, Permissions { nodeIndex, block.timestamp + ( isSchains ? - IConstantsHolder(contractManager.getContract("ConstantsHolder")).rotationDelay() : + IConstantsHolder(contractManager.getContract("ConstantsHolder")) + .rotationDelay() : 0 ) ); @@ -195,12 +203,23 @@ contract SkaleManager is IERC777Recipient, ISkaleManager, Permissions { IDistributor distributor = IDistributor(contractManager.getContract("Distributor")); require( - IMintableToken(address(skaleToken)).mint(address(distributor), bounty, abi.encode(validatorId), ""), + IMintableToken(address(skaleToken)).mint( + address(distributor), + bounty, + abi.encode(validatorId), + "" + ), "Token was not minted" ); } - function _refundGasByValidator(uint256 validatorId, address payable spender, uint256 gasLimit) private { + function _refundGasByValidator( + uint256 validatorId, + address payable spender, + uint256 gasLimit + ) + private + { IWallets(payable(contractManager.getContract("Wallets"))) .refundGasByValidator(validatorId, spender, gasLimit); } diff --git a/contracts/SkaleToken.sol b/contracts/SkaleToken.sol index 5e25bb66b..23ec89fd6 100644 --- a/contracts/SkaleToken.sol +++ b/contracts/SkaleToken.sol @@ -23,10 +23,18 @@ pragma solidity 0.8.17; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol"; -import { ContextUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; -import { IDelegatableToken } from "@skalenetwork/skale-manager-interfaces/delegation/IDelegatableToken.sol"; -import { IMintableToken } from "@skalenetwork/skale-manager-interfaces/IMintableToken.sol"; -import { IDelegationController } from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; +import { + ContextUpgradeable +} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; +import { + IDelegatableToken +} from "@skalenetwork/skale-manager-interfaces/delegation/IDelegatableToken.sol"; +import { + IMintableToken +} from "@skalenetwork/skale-manager-interfaces/IMintableToken.sol"; +import { + IDelegationController +} from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; import { ILocker } from "@skalenetwork/skale-manager-interfaces/delegation/ILocker.sol"; import { Context, ERC777 } from "./thirdparty/openzeppelin/ERC777.sol"; @@ -48,7 +56,8 @@ contract SkaleToken is ERC777, Permissions, ReentrancyGuard, IDelegatableToken, uint256 public constant DECIMALS = 18; - uint256 public constant CAP = 7 * 1e9 * (10 ** DECIMALS); // the maximum amount of tokens that can ever be created + // the maximum amount of tokens that can ever be created + uint256 public constant CAP = 7 * 1e9 * (10 ** DECIMALS); constructor(address contractsAddress, address[] memory defOps) ERC777("SKALE", "SKL", defOps) @@ -92,7 +101,13 @@ contract SkaleToken is ERC777, Permissions, ReentrancyGuard, IDelegatableToken, /** * @dev See {IDelegatableToken-getAndUpdateDelegatedAmount}. */ - function getAndUpdateDelegatedAmount(address wallet) external override returns (uint256 amount) { + function getAndUpdateDelegatedAmount( + address wallet + ) + external + override + returns (uint256 amount) + { return IDelegationController(contractManager.getContract("DelegationController")) .getAndUpdateDelegatedAmount(wallet); } @@ -122,7 +137,10 @@ contract SkaleToken is ERC777, Permissions, ReentrancyGuard, IDelegatableToken, { uint256 locked = getAndUpdateLockedAmount(from); if (locked > 0) { - require(balanceOf(from) >= locked.add(tokenId), "Token should be unlocked for transferring"); + require( + balanceOf(from) >= locked.add(tokenId), + "Token should be unlocked for transferring" + ); } } @@ -164,13 +182,24 @@ contract SkaleToken is ERC777, Permissions, ReentrancyGuard, IDelegatableToken, }); } - // we have to override _msgData() and _msgSender() functions because of collision in Context and ContextUpgradeable + // we have to override _msgData() and _msgSender() functions + // because of collision in Context and ContextUpgradeable - function _msgData() internal view override(Context, ContextUpgradeable) returns (bytes calldata msgData) { + function _msgData() + internal + view + override(Context, ContextUpgradeable) + returns (bytes calldata msgData) + { return Context._msgData(); } - function _msgSender() internal view override(Context, ContextUpgradeable) returns (address sender) { + function _msgSender() + internal + view + override(Context, ContextUpgradeable) + returns (address sender) + { return Context._msgSender(); } } diff --git a/contracts/SkaleVerifier.sol b/contracts/SkaleVerifier.sol index 7bdb6f33d..54e1f14c5 100644 --- a/contracts/SkaleVerifier.sol +++ b/contracts/SkaleVerifier.sol @@ -124,7 +124,9 @@ contract SkaleVerifier is Permissions, ISkaleVerifier { 3, Fp2Operations.P ); - if (hashB < Fp2Operations.P / 2 || mulmod(hashB, hashB, Fp2Operations.P) != ySquared || xCoord != hashA) { + if (hashB < Fp2Operations.P / 2 + || mulmod(hashB, hashB, Fp2Operations.P) != ySquared + || xCoord != hashA) { return false; } diff --git a/contracts/SyncManager.sol b/contracts/SyncManager.sol index 1571a82f1..09363fef1 100644 --- a/contracts/SyncManager.sol +++ b/contracts/SyncManager.sol @@ -47,8 +47,19 @@ contract SyncManager is Permissions, ISyncManager { Permissions.initialize(contractManagerAddress); } - function addIPRange(string memory name, bytes4 startIP, bytes4 endIP) external override onlySyncManager { - require(startIP <= endIP && startIP != bytes4(0) && endIP != bytes4(0), "Invalid IP ranges provided"); + function addIPRange( + string memory name, + bytes4 startIP, + bytes4 endIP + ) + external + override + onlySyncManager + { + require( + startIP <= endIP && startIP != bytes4(0) && endIP != bytes4(0), + "Invalid IP ranges provided" + ); bytes32 ipRangeNameHash = keccak256(abi.encodePacked(name)); require(_ipRangeNames.add(ipRangeNameHash), "IP range name is already taken"); ipRanges[ipRangeNameHash] = IPRange(startIP, endIP); @@ -66,12 +77,26 @@ contract SyncManager is Permissions, ISyncManager { return _ipRangeNames.length(); } - function getIPRangeByIndex(uint256 index) external view override returns (IPRange memory range) { + function getIPRangeByIndex( + uint256 index + ) + external + view + override + returns (IPRange memory range) + { bytes32 ipRangeNameHash = _ipRangeNames.at(index); return ipRanges[ipRangeNameHash]; } - function getIPRangeByName(string memory name) external view override returns (IPRange memory range) { + function getIPRangeByName( + string memory name + ) + external + view + override + returns (IPRange memory range) + { bytes32 ipRangeNameHash = keccak256(abi.encodePacked(name)); return ipRanges[ipRangeNameHash]; } diff --git a/contracts/Wallets.sol b/contracts/Wallets.sol index 38dec0fa0..ab76cfd9f 100644 --- a/contracts/Wallets.sol +++ b/contracts/Wallets.sol @@ -23,10 +23,14 @@ pragma solidity 0.8.17; -import { AddressUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; +import { + AddressUpgradeable +} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import { IWallets } from "@skalenetwork/skale-manager-interfaces/IWallets.sol"; import { ISchainsInternal } from "@skalenetwork/skale-manager-interfaces/ISchainsInternal.sol"; -import { IValidatorService } from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; +import { + IValidatorService +} from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; import { IConstantsHolder } from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; @@ -98,8 +102,10 @@ contract Wallets is Permissions, IWallets { * so validator or schain owner can use usual transfer ether to recharge wallet. */ receive() external payable override { - IValidatorService validatorService = IValidatorService(contractManager.getContract("ValidatorService")); - ISchainsInternal schainsInternal = ISchainsInternal(contractManager.getContract("SchainsInternal")); + IValidatorService validatorService = + IValidatorService(contractManager.getContract("ValidatorService")); + ISchainsInternal schainsInternal = + ISchainsInternal(contractManager.getContract("SchainsInternal")); bytes32[] memory schainHashes = schainsInternal.getSchainHashesByAddress(msg.sender); if (schainHashes.length == 1) { rechargeSchainWallet(schainHashes[0]); @@ -131,10 +137,14 @@ contract Wallets is Permissions, IWallets { { require(spender != address(0), "Spender must be specified"); require(validatorId != 0, "ValidatorId could not be zero"); - uint256 minNodeBalance = IConstantsHolder(contractManager.getContract("ConstantsHolder")).minNodeBalance(); + uint256 minNodeBalance = IConstantsHolder(contractManager.getContract("ConstantsHolder")) + .minNodeBalance(); uint256 actualSpenderBalance = spender.balance + gasLimit * tx.gasprice; if (minNodeBalance > actualSpenderBalance) { - uint256 amount = Math.min(_validatorWallets[validatorId], minNodeBalance - actualSpenderBalance); + uint256 amount = Math.min( + _validatorWallets[validatorId], + minNodeBalance - actualSpenderBalance + ); _validatorWallets[validatorId] -= amount; emit NodeRefundedByValidator(spender, validatorId, amount); spender.transfer(amount); @@ -149,7 +159,14 @@ contract Wallets is Permissions, IWallets { * Emits a {ReturnDebtFromValidator} event. * */ - function refundGasByValidatorToSchain(uint256 validatorId, bytes32 schainHash) external override allow("SkaleDKG") { + function refundGasByValidatorToSchain( + uint256 validatorId, + bytes32 schainHash + ) + external + override + allow("SkaleDKG") + { uint256 debtAmount = _schainDebts[schainHash]; uint256 validatorWallet = _validatorWallets[validatorId]; if (debtAmount <= validatorWallet) { @@ -223,7 +240,8 @@ contract Wallets is Permissions, IWallets { * - `msg.sender` should be a validator address */ function withdrawFundsFromValidatorWallet(uint256 amount) external override { - IValidatorService validatorService = IValidatorService(contractManager.getContract("ValidatorService")); + IValidatorService validatorService = + IValidatorService(contractManager.getContract("ValidatorService")); uint256 validatorId = validatorService.getValidatorId(msg.sender); require(amount <= _validatorWallets[validatorId], "Balance is too low"); _validatorWallets[validatorId] = _validatorWallets[validatorId] - amount; @@ -241,7 +259,14 @@ contract Wallets is Permissions, IWallets { /** * @dev Returns validator eth balance. */ - function getValidatorBalance(uint256 validatorId) external view override returns (uint256 balance) { + function getValidatorBalance( + uint256 validatorId + ) + external + view + override + returns (uint256 balance) + { return _validatorWallets[validatorId]; } @@ -254,7 +279,8 @@ contract Wallets is Permissions, IWallets { * - Given validator must exist */ function rechargeValidatorWallet(uint256 validatorId) public payable override { - IValidatorService validatorService = IValidatorService(contractManager.getContract("ValidatorService")); + IValidatorService validatorService = + IValidatorService(contractManager.getContract("ValidatorService")); require(validatorService.validatorExists(validatorId), "Validator does not exists"); _validatorWallets[validatorId] = _validatorWallets[validatorId] + msg.value; emit ValidatorWalletRecharged(msg.sender, msg.value, validatorId); @@ -269,8 +295,12 @@ contract Wallets is Permissions, IWallets { * - Given schain must be created */ function rechargeSchainWallet(bytes32 schainHash) public payable override { - ISchainsInternal schainsInternal = ISchainsInternal(contractManager.getContract("SchainsInternal")); - require(schainsInternal.isSchainActive(schainHash), "Schain should be active for recharging"); + ISchainsInternal schainsInternal = + ISchainsInternal(contractManager.getContract("SchainsInternal")); + require( + schainsInternal.isSchainActive(schainHash), + "Schain should be active for recharging" + ); _schainWallets[schainHash] = _schainWallets[schainHash] + msg.value; emit SchainWalletRecharged(msg.sender, msg.value, schainHash); } diff --git a/contracts/delegation/DelegationController.sol b/contracts/delegation/DelegationController.sol index a34c48b98..3d6384508 100644 --- a/contracts/delegation/DelegationController.sol +++ b/contracts/delegation/DelegationController.sol @@ -22,22 +22,27 @@ 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"; +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 @@ -54,7 +59,8 @@ import { PartialDifferences } from "./PartialDifferences.sol"; * * - 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. + * - 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. @@ -73,7 +79,7 @@ contract DelegationController is Permissions, ILocker, IDelegationController { struct SlashingLog { // month => slashing event - mapping (uint256 => SlashingLogEvent) slashes; + mapping(uint256 => SlashingLogEvent) slashes; uint256 firstMonth; uint256 lastMonth; } @@ -102,57 +108,61 @@ contract DelegationController is Permissions, ILocker, IDelegationController { // month uint256 value; //validatorId => month - mapping (uint256 => uint256) byValidator; + mapping(uint256 => uint256) byValidator; } struct ValidatorsStatistics { // number of validators uint256 number; //validatorId => amount of delegations - mapping (uint256 => uint256) delegated; + mapping(uint256 => uint256) delegated; } - uint256 public constant UNDELEGATION_PROHIBITION_WINDOW_SECONDS = 3 * 24 * 60 * 60; + 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; + mapping(uint256 => uint256[]) public delegationsByValidator; // holder => delegationId[] - mapping (address => uint256[]) public delegationsByHolder; + mapping(address => uint256[]) public delegationsByHolder; // delegationId => extras mapping(uint256 => DelegationExtras) private _delegationExtras; // validatorId => sequence - mapping (uint256 => PartialDifferences.Value) private _delegatedToValidator; + mapping(uint256 => PartialDifferences.Value) private _delegatedToValidator; // validatorId => sequence - mapping (uint256 => PartialDifferences.Sequence) private _effectiveDelegatedToValidator; + mapping(uint256 => PartialDifferences.Sequence) + private _effectiveDelegatedToValidator; // validatorId => slashing log - mapping (uint256 => SlashingLog) private _slashesOfValidator; + mapping(uint256 => SlashingLog) private _slashesOfValidator; // holder => sequence - mapping (address => PartialDifferences.Value) private _delegatedByHolder; + mapping(address => PartialDifferences.Value) private _delegatedByHolder; // holder => validatorId => sequence - mapping (address => mapping (uint256 => PartialDifferences.Value)) private _delegatedByHolderToValidator; + mapping(address => mapping(uint256 => PartialDifferences.Value)) + private _delegatedByHolderToValidator; // holder => validatorId => sequence - mapping (address => mapping (uint256 => PartialDifferences.Sequence)) - private _effectiveDelegatedByHolderToValidator; + mapping(address => mapping(uint256 => PartialDifferences.Sequence)) + private _effectiveDelegatedByHolderToValidator; SlashingEvent[] private _slashes; // holder => index in _slashes; - mapping (address => uint256) private _firstUnprocessedSlashByHolder; + mapping(address => uint256) private _firstUnprocessedSlashByHolder; // holder => validatorId => month - mapping (address => FirstDelegationMonth) private _firstDelegationMonth; + mapping(address => FirstDelegationMonth) private _firstDelegationMonth; // holder => locked in pending - mapping (address => LockedInPending) private _lockedInPendingDelegations; + mapping(address => LockedInPending) private _lockedInPendingDelegations; - mapping (address => ValidatorsStatistics) private _numberOfValidatorsPerDelegator; + mapping(address => ValidatorsStatistics) + private _numberOfValidatorsPerDelegator; /** * @dev Modifier to make a function callable only if delegation exists. @@ -169,14 +179,19 @@ contract DelegationController is Permissions, ILocker, IDelegationController { /** * @dev Update and return a validator's delegations. */ - function getAndUpdateDelegatedToValidatorNow(uint256 validatorId) external override returns (uint256 amount) { - return _getAndUpdateDelegatedToValidator(validatorId, _getCurrentMonth()); + 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) { + function getAndUpdateDelegatedAmount( + address holder + ) external override returns (uint256 amount) { return _getAndUpdateDelegatedByHolder(holder); } @@ -184,15 +199,21 @@ contract DelegationController is Permissions, ILocker, IDelegationController { * @dev Update and return the effective amount delegated (minus slash) for * the given month. */ - function getAndUpdateEffectiveDelegatedByHolderToValidator(address holder, uint256 validatorId, uint256 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); + SlashingSignal[] + memory slashingSignals = _processAllSlashesWithoutSignals(holder); + effectiveDelegated = _effectiveDelegatedByHolderToValidator[holder][ + validatorId + ].getAndUpdateValueInSequence(month); _sendSlashingSignals(slashingSignals); } @@ -219,17 +240,23 @@ contract DelegationController is Permissions, ILocker, IDelegationController { uint256 amount, uint256 delegationPeriod, string calldata info - ) - external - override - { + ) external override { require( - _getDelegationPeriodManager().isDelegationPeriodAllowed(delegationPeriod), - "This delegation period is not allowed"); - _getValidatorService().checkValidatorCanReceiveDelegation(validatorId, amount); + _getDelegationPeriodManager().isDelegationPeriodAllowed( + delegationPeriod + ), + "This delegation period is not allowed" + ); + _getValidatorService().checkValidatorCanReceiveDelegation( + validatorId, + amount + ); _checkIfDelegationIsAllowed(msg.sender, validatorId); - SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(msg.sender); + SlashingSignal[] + memory slashingSignals = _processAllSlashesWithoutSignals( + msg.sender + ); uint256 delegationId = _addDelegation({ holder: msg.sender, @@ -240,10 +267,15 @@ contract DelegationController is Permissions, ILocker, IDelegationController { }); // 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"); + 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); @@ -253,14 +285,18 @@ contract DelegationController is Permissions, ILocker, IDelegationController { /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ - function getAndUpdateLockedAmount(address wallet) external override returns (uint256 amount) { + 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) { + function getAndUpdateForbiddenForDelegationAmount( + address wallet + ) external override returns (uint256 amount) { return _getAndUpdateLockedAmount(wallet); } @@ -274,12 +310,23 @@ contract DelegationController is Permissions, ILocker, IDelegationController { * - `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"); + 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); + _subtractFromLockedInPendingDelegations( + delegations[delegationId].holder, + delegations[delegationId].amount + ); emit DelegationRequestCanceledByUser(delegationId); } @@ -297,10 +344,16 @@ contract DelegationController is Permissions, ILocker, IDelegationController { * - Validator must be recipient of proposal. * - Delegation state must be PROPOSED. */ - function acceptPendingDelegation(uint256 delegationId) external override checkDelegationExists(delegationId) { + function acceptPendingDelegation( + uint256 delegationId + ) external override checkDelegationExists(delegationId) { require( - _getValidatorService().checkValidatorAddressToId(msg.sender, delegations[delegationId].validatorId), - "No permissions to accept request"); + _getValidatorService().checkValidatorAddressToId( + msg.sender, + delegations[delegationId].validatorId + ), + "No permissions to accept request" + ); _accept(delegationId); } @@ -314,23 +367,35 @@ contract DelegationController is Permissions, ILocker, IDelegationController { * - `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"); + 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"); + (validatorService.validatorAddressExists(msg.sender) && + delegations[delegationId].validatorId == + validatorService.getValidatorId(msg.sender)), + "Permission denied to request undelegation" + ); _removeValidatorFromValidatorsPerDelegators( delegations[delegationId].holder, - delegations[delegationId].validatorId); + delegations[delegationId].validatorId + ); processAllSlashes(msg.sender); - delegations[delegationId].finished = _calculateDelegationEndMonth(delegationId); + delegations[delegationId].finished = _calculateDelegationEndMonth( + delegationId + ); require( - block.timestamp + UNDELEGATION_PROHIBITION_WINDOW_SECONDS - < _getTimeHelpers().monthToTimestamp(delegations[delegationId].finished), + block.timestamp + UNDELEGATION_PROHIBITION_WINDOW_SECONDS < + _getTimeHelpers().monthToTimestamp( + delegations[delegationId].finished + ), "Undelegation requests must be sent 3 days before the end of delegation period" ); @@ -350,7 +415,10 @@ contract DelegationController is Permissions, ILocker, IDelegationController { * * See {Punisher}. */ - function confiscate(uint256 validatorId, uint256 amount) external override allow("Punisher") { + function confiscate( + uint256 validatorId, + uint256 amount + ) external override allow("Punisher") { uint256 currentMonth = _getCurrentMonth(); FractionUtils.Fraction memory coefficient = _delegatedToValidator[validatorId].reduceValue(amount, currentMonth); @@ -363,25 +431,34 @@ contract DelegationController is Permissions, ILocker, IDelegationController { _effectiveDelegatedToValidator[validatorId].lastChangedMonth - currentMonth ); for (uint256 i = 0; i < initialSubtractions.length; ++i) { - initialSubtractions[i] = _effectiveDelegatedToValidator[validatorId] - .subtractDiff[currentMonth + i + 1]; + 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})); + _slashes.push( + SlashingEvent({ + reducingCoefficient: coefficient, + validatorId: validatorId, + month: currentMonth + }) + ); IBountyV2 bounty = _getBounty(); bounty.handleDelegationRemoving( initialEffectiveDelegated - - _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(currentMonth), + _effectiveDelegatedToValidator[validatorId] + .getAndUpdateValueInSequence(currentMonth), currentMonth ); for (uint256 i = 0; i < initialSubtractions.length; ++i) { bounty.handleDelegationAdd( initialSubtractions[i] - - _effectiveDelegatedToValidator[validatorId].subtractDiff[currentMonth + i + 1], + _effectiveDelegatedToValidator[validatorId].subtractDiff[ + currentMonth + i + 1 + ], currentMonth + i + 1 ); } @@ -392,66 +469,66 @@ contract DelegationController is Permissions, ILocker, IDelegationController { * @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) + function getAndUpdateEffectiveDelegatedToValidator( + uint256 validatorId, + uint256 month + ) external override allowTwo("Bounty", "Distributor") returns (uint256 amount) { - return _effectiveDelegatedToValidator[validatorId].getAndUpdateValueInSequence(month); + 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 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(); + ) 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); + ) external view override returns (uint256 amount) { + return + _effectiveDelegatedToValidator[validatorId].getValueInSequence( + month + ); } function getDelegatedToValidator( uint256 validatorId, uint256 month - ) - external - view - override - returns (uint256 amount) - { + ) external view override returns (uint256 amount) { return _delegatedToValidator[validatorId].getValue(month); } /** * @dev Return Delegation struct. */ - function getDelegation(uint256 delegationId) + function getDelegation( + uint256 delegationId + ) external view override @@ -467,26 +544,25 @@ contract DelegationController is Permissions, ILocker, IDelegationController { function getFirstDelegationMonth( address holder, uint256 validatorId - ) - external - view - override - returns(uint256 month) - { + ) 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) { + 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) { + function getDelegationsByHolderLength( + address holder + ) external view override returns (uint256 length) { return delegationsByHolder[holder].length; } @@ -508,7 +584,9 @@ contract DelegationController is Permissions, ILocker, IDelegationController { /** * @dev Returns the token state of a given delegation. */ - function getState(uint256 delegationId) + function getState( + uint256 delegationId + ) public view override @@ -517,7 +595,12 @@ contract DelegationController is Permissions, ILocker, IDelegationController { { if (delegations[delegationId].started == 0) { if (delegations[delegationId].finished == 0) { - if (_getCurrentMonth() == _getTimeHelpers().timestampToMonth(delegations[delegationId].created)) { + if ( + _getCurrentMonth() == + _getTimeHelpers().timestampToMonth( + delegations[delegationId].created + ) + ) { return State.PROPOSED; } else { return State.REJECTED; @@ -532,7 +615,9 @@ contract DelegationController is Permissions, ILocker, IDelegationController { if (delegations[delegationId].finished == 0) { return State.DELEGATED; } else { - if (_getCurrentMonth() < delegations[delegationId].finished) { + if ( + _getCurrentMonth() < delegations[delegationId].finished + ) { return State.UNDELEGATION_REQUESTED; } else { return State.COMPLETED; @@ -545,7 +630,9 @@ contract DelegationController is Permissions, ILocker, IDelegationController { /** * @dev Returns the amount of tokens in PENDING delegation state. */ - function getLockedInPendingDelegations(address holder) public view override returns (uint256 amount) { + function getLockedInPendingDelegations( + address holder + ) public view override returns (uint256 amount) { uint256 currentMonth = _getCurrentMonth(); if (_lockedInPendingDelegations[holder].month < currentMonth) { return 0; @@ -557,8 +644,12 @@ contract DelegationController is Permissions, ILocker, IDelegationController { /** * @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; + function hasUnprocessedSlashes( + address holder + ) public view override returns (bool hasUnprocessed) { + return + _everDelegated(holder) && + _firstUnprocessedSlashByHolder[holder] < _slashes.length; } // private @@ -567,9 +658,10 @@ contract DelegationController is Permissions, ILocker, IDelegationController { * @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) - { + function _getAndUpdateDelegatedToValidator( + uint256 validatorId, + uint256 month + ) private returns (uint256 amount) { return _delegatedToValidator[validatorId].getAndUpdateValue(month); } @@ -582,63 +674,106 @@ contract DelegationController is Permissions, ILocker, IDelegationController { uint256 amount, uint256 delegationPeriod, string memory info - ) - private - returns (uint256 delegationId) - { + ) 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 - })); + 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); + _addToLockedInPendingDelegations( + delegations[delegationId].holder, + delegations[delegationId].amount + ); } - function _addToDelegatedToValidator(uint256 validatorId, uint256 amount, uint256 month) private { + 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 _addToEffectiveDelegatedToValidator( + uint256 validatorId, + uint256 effectiveAmount, + uint256 month + ) private { + _effectiveDelegatedToValidator[validatorId].addToSequence( + effectiveAmount, + month + ); } - function _addToDelegatedByHolder(address holder, uint256 amount, uint256 month) private { + 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); + 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) { + 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 { + 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); + 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) { + function _removeValidatorFromValidatorsPerDelegators( + address holder, + uint256 validatorId + ) private { + if ( + _numberOfValidatorsPerDelegator[holder].delegated[validatorId] == 1 + ) { _numberOfValidatorsPerDelegator[holder].number -= 1; } _numberOfValidatorsPerDelegator[holder].delegated[validatorId] -= 1; @@ -648,23 +783,25 @@ contract DelegationController is Permissions, ILocker, IDelegationController { address holder, uint256 validatorId, uint256 effectiveAmount, - uint256 month) - private - { - _effectiveDelegatedByHolderToValidator[holder][validatorId].addToSequence(effectiveAmount, month); + 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); + uint256 month + ) private { + _effectiveDelegatedByHolderToValidator[holder][validatorId] + .subtractFromSequence(effectiveAmount, month); } - function _getAndUpdateDelegatedByHolder(address holder) private returns (uint256 amount) { + function _getAndUpdateDelegatedByHolder( + address holder + ) private returns (uint256 amount) { uint256 currentMonth = _getCurrentMonth(); processAllSlashes(holder); return _delegatedByHolder[holder].getAndUpdateValue(currentMonth); @@ -673,37 +810,56 @@ contract DelegationController is Permissions, ILocker, IDelegationController { function _getAndUpdateDelegatedByHolderToValidator( address holder, uint256 validatorId, - uint256 month) - private returns (uint256 amount) - { - return _delegatedByHolderToValidator[holder][validatorId].getAndUpdateValue(month); + uint256 month + ) private returns (uint256 amount) { + return + _delegatedByHolderToValidator[holder][validatorId] + .getAndUpdateValue(month); } - function _addToLockedInPendingDelegations(address holder, uint256 amount) private { + 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; + _lockedInPendingDelegations[holder].amount = + _lockedInPendingDelegations[holder].amount + + amount; } } - function _subtractFromLockedInPendingDelegations(address holder, uint256 amount) private { + function _subtractFromLockedInPendingDelegations( + address holder, + uint256 amount + ) private { uint256 currentMonth = _getCurrentMonth(); assert(_lockedInPendingDelegations[holder].month == currentMonth); - _lockedInPendingDelegations[holder].amount = _lockedInPendingDelegations[holder].amount - amount; + _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 _getAndUpdateLockedAmount( + address wallet + ) private returns (uint256 amount) { + return + _getAndUpdateDelegatedByHolder(wallet) + + getLockedInPendingDelegations(wallet); } - function _updateFirstDelegationMonth(address holder, uint256 validatorId, uint256 month) private { + function _updateFirstDelegationMonth( + address holder, + uint256 validatorId, + uint256 month + ) private { if (_firstDelegationMonth[holder].value == 0) { _firstDelegationMonth[holder].value = month; _firstUnprocessedSlashByHolder[holder] = _slashes.length; @@ -713,7 +869,11 @@ contract DelegationController is Permissions, ILocker, IDelegationController { } } - function _removeFromDelegatedToValidator(uint256 validatorId, uint256 amount, uint256 month) private { + function _removeFromDelegatedToValidator( + uint256 validatorId, + uint256 amount, + uint256 month + ) private { _delegatedToValidator[validatorId].subtractFromValue(amount, month); } @@ -721,28 +881,33 @@ contract DelegationController is Permissions, ILocker, IDelegationController { uint256 validatorId, uint256 effectiveAmount, uint256 month - ) - private - { - _effectiveDelegatedToValidator[validatorId].subtractFromSequence(effectiveAmount, month); + ) private { + _effectiveDelegatedToValidator[validatorId].subtractFromSequence( + effectiveAmount, + month + ); } function _putToSlashingLog( SlashingLog storage log, FractionUtils.Fraction memory coefficient, - uint256 month) - private - { + 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"); + 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); + log.slashes[month].reducingCoefficient = log + .slashes[month] + .reducingCoefficient + .multiplyFraction(coefficient); } else { log.slashes[month].reducingCoefficient = coefficient; log.slashes[month].nextMonth = 0; @@ -752,9 +917,10 @@ contract DelegationController is Permissions, ILocker, IDelegationController { } } - function _processSlashesWithoutSignals(address holder, uint256 limit) - private returns (SlashingSignal[] memory slashingSignals) - { + function _processSlashesWithoutSignals( + address holder, + uint256 limit + ) private returns (SlashingSignal[] memory slashingSignals) { if (hasUnprocessedSlashes(holder)) { uint256 index = _firstUnprocessedSlashByHolder[holder]; uint256 end = _slashes.length; @@ -766,31 +932,47 @@ contract DelegationController is Permissions, ILocker, IDelegationController { for (; index < end; ++index) { uint256 validatorId = _slashes[index].validatorId; uint256 month = _slashes[index].month; - uint256 oldValue = _getAndUpdateDelegatedByHolderToValidator(holder, validatorId, 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); + _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)); + slashingSignals[index - begin].penalty = oldValue + .boundedSub( + _getAndUpdateDelegatedByHolderToValidator( + holder, + validatorId, + month + ) + ); } } _firstUnprocessedSlashByHolder[holder] = end; } } - function _processAllSlashesWithoutSignals(address holder) - private returns (SlashingSignal[] memory slashingSignals) - { + function _processAllSlashesWithoutSignals( + address holder + ) private returns (SlashingSignal[] memory slashingSignals) { return _processSlashesWithoutSignals(holder, 0); } - function _sendSlashingSignals(SlashingSignal[] memory slashingSignals) private { + function _sendSlashingSignals( + SlashingSignal[] memory slashingSignals + ) private { IPunisher punisher = IPunisher(contractManager.getPunisher()); address previousHolder = address(0); uint256 accumulatedPenalty = 0; @@ -802,7 +984,9 @@ contract DelegationController is Permissions, ILocker, IDelegationController { previousHolder = slashingSignals[i].holder; accumulatedPenalty = slashingSignals[i].penalty; } else { - accumulatedPenalty = accumulatedPenalty + slashingSignals[i].penalty; + accumulatedPenalty = + accumulatedPenalty + + slashingSignals[i].penalty; } } if (accumulatedPenalty > 0) { @@ -814,38 +998,48 @@ contract DelegationController is Permissions, ILocker, IDelegationController { uint256 currentMonth = _getCurrentMonth(); delegations[delegationId].started = currentMonth + 1; if (_slashesOfValidator[delegations[delegationId].validatorId].lastMonth > 0) { - _delegationExtras[delegationId].lastSlashingMonthBeforeDelegation = - _slashesOfValidator[delegations[delegationId].validatorId].lastMonth; + _delegationExtras[delegationId] + .lastSlashingMonthBeforeDelegation = _slashesOfValidator[ + delegations[delegationId].validatorId + ].lastMonth; } _addToDelegatedToValidator( delegations[delegationId].validatorId, delegations[delegationId].amount, - currentMonth + 1); + currentMonth + 1 + ); _addToDelegatedByHolder( delegations[delegationId].holder, delegations[delegationId].amount, - currentMonth + 1); + currentMonth + 1 + ); _addToDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, delegations[delegationId].amount, - currentMonth + 1); + currentMonth + 1 + ); _updateFirstDelegationMonth( delegations[delegationId].holder, delegations[delegationId].validatorId, - currentMonth + 1); + currentMonth + 1 + ); uint256 effectiveAmount = delegations[delegationId].amount * - _getDelegationPeriodManager().stakeMultipliers(delegations[delegationId].delegationPeriod); + _getDelegationPeriodManager().stakeMultipliers( + delegations[delegationId].delegationPeriod + ); _addToEffectiveDelegatedToValidator( delegations[delegationId].validatorId, effectiveAmount, - currentMonth + 1); + currentMonth + 1 + ); _addToEffectiveDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, effectiveAmount, - currentMonth + 1); + currentMonth + 1 + ); _addValidatorToValidatorsPerDelegators( delegations[delegationId].holder, delegations[delegationId].validatorId @@ -853,46 +1047,60 @@ contract DelegationController is Permissions, ILocker, IDelegationController { } function _subtractFromAllStatistics(uint256 delegationId) private { - uint256 amountAfterSlashing = _calculateDelegationAmountAfterSlashing(delegationId); + uint256 amountAfterSlashing = _calculateDelegationAmountAfterSlashing( + delegationId + ); _removeFromDelegatedToValidator( delegations[delegationId].validatorId, amountAfterSlashing, - delegations[delegationId].finished); + delegations[delegationId].finished + ); _removeFromDelegatedByHolder( delegations[delegationId].holder, amountAfterSlashing, - delegations[delegationId].finished); + delegations[delegationId].finished + ); _removeFromDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, amountAfterSlashing, - delegations[delegationId].finished); + delegations[delegationId].finished + ); uint256 effectiveAmount = amountAfterSlashing * - _getDelegationPeriodManager().stakeMultipliers(delegations[delegationId].delegationPeriod); + _getDelegationPeriodManager().stakeMultipliers( + delegations[delegationId].delegationPeriod + ); _removeFromEffectiveDelegatedToValidator( delegations[delegationId].validatorId, effectiveAmount, - delegations[delegationId].finished); + delegations[delegationId].finished + ); _removeFromEffectiveDelegatedByHolderToValidator( delegations[delegationId].holder, delegations[delegationId].validatorId, effectiveAmount, - delegations[delegationId].finished); + delegations[delegationId].finished + ); _getBounty().handleDelegationRemoving( effectiveAmount, - delegations[delegationId].finished); + delegations[delegationId].finished + ); } function _accept(uint256 delegationId) private { - _checkIfDelegationIsAllowed(delegations[delegationId].holder, delegations[delegationId].validatorId); + _checkIfDelegationIsAllowed( + delegations[delegationId].holder, + delegations[delegationId].validatorId + ); State currentState = getState(delegationId); if (currentState != State.PROPOSED) { - if (currentState == State.ACCEPTED || + if ( + currentState == State.ACCEPTED || currentState == State.DELEGATED || currentState == State.UNDELEGATION_REQUESTED || - currentState == State.COMPLETED) - { + currentState == State.COMPLETED + ) { revert("The delegation has been already accepted"); } else if (currentState == State.CANCELED) { revert("The delegation has been cancelled by token holder"); @@ -900,16 +1108,24 @@ contract DelegationController is Permissions, ILocker, IDelegationController { revert("The delegation request is outdated"); } } - require(currentState == State.PROPOSED, "Cannot set delegation state to accepted"); + require( + currentState == State.PROPOSED, + "Cannot set delegation state to accepted" + ); - SlashingSignal[] memory slashingSignals = _processAllSlashesWithoutSignals(delegations[delegationId].holder); + SlashingSignal[] + memory slashingSignals = _processAllSlashesWithoutSignals( + delegations[delegationId].holder + ); _addToAllStatistics(delegationId); uint256 amount = delegations[delegationId].amount; uint256 effectiveAmount = amount * - _getDelegationPeriodManager().stakeMultipliers(delegations[delegationId].delegationPeriod); + _getDelegationPeriodManager().stakeMultipliers( + delegations[delegationId].delegationPeriod + ); _getBounty().handleDelegationAdd( effectiveAmount, delegations[delegationId].started @@ -926,30 +1142,41 @@ contract DelegationController is Permissions, ILocker, IDelegationController { /** * @dev Checks whether the holder has performed a delegation. */ - function _everDelegated(address holder) private view returns (bool delegated) { + 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) { + 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; + 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; + 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) { @@ -958,13 +1185,22 @@ contract DelegationController is Permissions, ILocker, IDelegationController { return amount; } } - for (uint256 i = startMonth; + for ( + uint256 i = startMonth; i > 0 && i < delegations[delegationId].finished; - i = _slashesOfValidator[validatorId].slashes[i].nextMonth) { + 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; + amount = + (amount * + _slashesOfValidator[validatorId] + .slashes[i] + .reducingCoefficient + .numerator) / + _slashesOfValidator[validatorId] + .slashes[i] + .reducingCoefficient + .denominator; } } return amount; @@ -978,23 +1214,39 @@ contract DelegationController is Permissions, ILocker, IDelegationController { * - 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 { + function _checkIfDelegationIsAllowed( + address holder, + uint256 validatorId + ) private view { require( - _numberOfValidatorsPerDelegator[holder].delegated[validatorId] > 0 || - _numberOfValidatorsPerDelegator[holder].number < _getConstantsHolder().limitValidatorsPerDelegator(), + _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 _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) { + function _getValidatorService() + private + view + returns (IValidatorService validatorService) + { return IValidatorService(contractManager.getValidatorService()); } @@ -1002,7 +1254,11 @@ contract DelegationController is Permissions, ILocker, IDelegationController { return ITimeHelpers(contractManager.getTimeHelpers()); } - function _getConstantsHolder() private view returns (IConstantsHolder constantsHolder) { + function _getConstantsHolder() + private + view + returns (IConstantsHolder constantsHolder) + { return IConstantsHolder(contractManager.getConstantsHolder()); } } diff --git a/contracts/delegation/DelegationPeriodManager.sol b/contracts/delegation/DelegationPeriodManager.sol index b015c2eae..a1624d6d9 100644 --- a/contracts/delegation/DelegationPeriodManager.sol +++ b/contracts/delegation/DelegationPeriodManager.sol @@ -22,10 +22,11 @@ pragma solidity 0.8.17; -import { IDelegationPeriodManager } -from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationPeriodManager.sol"; +import { + IDelegationPeriodManager +} from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationPeriodManager.sol"; -import { Permissions } from "../Permissions.sol"; +import {Permissions} from "../Permissions.sol"; /** * @title Delegation Period Manager @@ -34,17 +35,17 @@ import { Permissions } from "../Permissions.sol"; * returns or `stakeMultiplier`. Currently, only delegation periods can be added. */ contract DelegationPeriodManager is Permissions, IDelegationPeriodManager { + mapping(uint256 => uint256) public stakeMultipliers; - mapping (uint256 => uint256) public stakeMultipliers; - - bytes32 public constant DELEGATION_PERIOD_SETTER_ROLE = keccak256("DELEGATION_PERIOD_SETTER_ROLE"); + bytes32 public constant DELEGATION_PERIOD_SETTER_ROLE = + keccak256("DELEGATION_PERIOD_SETTER_ROLE"); /** * @dev Initial delegation period and multiplier settings. */ function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); - stakeMultipliers[2] = 100; // 2 months at 100 + stakeMultipliers[2] = 100; // 2 months at 100 // stakeMultipliers[6] = 150; // 6 months at 150 // stakeMultipliers[12] = 200; // 12 months at 200 } @@ -55,9 +56,18 @@ contract DelegationPeriodManager is Permissions, IDelegationPeriodManager { * * Emits a {DelegationPeriodWasSet} event. */ - function setDelegationPeriod(uint256 monthsCount, uint256 stakeMultiplier) external override { - require(hasRole(DELEGATION_PERIOD_SETTER_ROLE, msg.sender), "DELEGATION_PERIOD_SETTER_ROLE is required"); - require(stakeMultipliers[monthsCount] == 0, "Delegation period is already set"); + function setDelegationPeriod( + uint256 monthsCount, + uint256 stakeMultiplier + ) external override { + require( + hasRole(DELEGATION_PERIOD_SETTER_ROLE, msg.sender), + "DELEGATION_PERIOD_SETTER_ROLE is required" + ); + require( + stakeMultipliers[monthsCount] == 0, + "Delegation period is already set" + ); stakeMultipliers[monthsCount] = stakeMultiplier; emit DelegationPeriodWasSet(monthsCount, stakeMultiplier); @@ -66,7 +76,9 @@ contract DelegationPeriodManager is Permissions, IDelegationPeriodManager { /** * @dev Checks whether given delegation period is allowed. */ - function isDelegationPeriodAllowed(uint256 monthsCount) external view override returns (bool allowed) { + function isDelegationPeriodAllowed( + uint256 monthsCount + ) external view override returns (bool allowed) { return stakeMultipliers[monthsCount] != 0; } } diff --git a/contracts/delegation/Distributor.sol b/contracts/delegation/Distributor.sol index 96a925fc8..4f3f9ff1b 100644 --- a/contracts/delegation/Distributor.sol +++ b/contracts/delegation/Distributor.sol @@ -21,19 +21,22 @@ pragma solidity 0.8.17; -import { IERC1820Registry } from "@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol"; -import { IERC777Recipient } from "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol"; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { IDistributor } from "@skalenetwork/skale-manager-interfaces/delegation/IDistributor.sol"; -import { IValidatorService } from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; -import { IDelegationController } from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; -import { ITimeHelpers } from "@skalenetwork/skale-manager-interfaces/delegation/ITimeHelpers.sol"; - -import { Permissions } from "../Permissions.sol"; -import { ConstantsHolder } from "../ConstantsHolder.sol"; -import { MathUtils } from "../utils/MathUtils.sol"; - +import {IERC1820Registry} from "@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol"; +import {IERC777Recipient} from "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import {IDistributor} from "@skalenetwork/skale-manager-interfaces/delegation/IDistributor.sol"; +import { + IValidatorService +} from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; +import { + IDelegationController +} from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; +import {ITimeHelpers} from "@skalenetwork/skale-manager-interfaces/delegation/ITimeHelpers.sol"; + +import {Permissions} from "../Permissions.sol"; +import {ConstantsHolder} from "../ConstantsHolder.sol"; +import {MathUtils} from "../utils/MathUtils.sol"; /** * @title Distributor @@ -46,18 +49,23 @@ contract Distributor is Permissions, IERC777Recipient, IDistributor { IERC1820Registry private _erc1820; // validatorId => month => token - mapping (uint256 => mapping (uint256 => uint256)) private _bountyPaid; + mapping(uint256 => mapping(uint256 => uint256)) private _bountyPaid; // validatorId => month => token - mapping (uint256 => mapping (uint256 => uint256)) private _feePaid; + mapping(uint256 => mapping(uint256 => uint256)) private _feePaid; // holder => validatorId => month - mapping (address => mapping (uint256 => uint256)) private _firstUnwithdrawnMonth; + mapping(address => mapping(uint256 => uint256)) + private _firstUnwithdrawnMonth; // validatorId => month - mapping (uint256 => uint256) private _firstUnwithdrawnMonthForValidator; + mapping(uint256 => uint256) private _firstUnwithdrawnMonthForValidator; function initialize(address contractsAddress) public override initializer { Permissions.initialize(contractsAddress); _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); - _erc1820.setInterfaceImplementer(address(this), keccak256("ERC777TokensRecipient"), address(this)); + _erc1820.setInterfaceImplementer( + address(this), + keccak256("ERC777TokensRecipient"), + address(this) + ); } /** @@ -65,11 +73,7 @@ contract Distributor is Permissions, IERC777Recipient, IDistributor { */ function getAndUpdateEarnedBountyAmount( uint256 validatorId - ) - external - override - returns (uint256 earned, uint256 endMonth) - { + ) external override returns (uint256 earned, uint256 endMonth) { return getAndUpdateEarnedBountyAmountOf(msg.sender, validatorId); } @@ -84,29 +88,35 @@ contract Distributor is Permissions, IERC777Recipient, IDistributor { * - Bounty must be unlocked. */ function withdrawBounty(uint256 validatorId, address to) external override { - ITimeHelpers timeHelpers = ITimeHelpers(contractManager.getContract("TimeHelpers")); - ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); + ITimeHelpers timeHelpers = ITimeHelpers( + contractManager.getContract("TimeHelpers") + ); + ConstantsHolder constantsHolder = ConstantsHolder( + contractManager.getContract("ConstantsHolder") + ); - require(block.timestamp >= timeHelpers.addMonths( - constantsHolder.launchTimestamp(), - constantsHolder.BOUNTY_LOCKUP_MONTHS() - ), "Bounty is locked"); + require( + block.timestamp >= + timeHelpers.addMonths( + constantsHolder.launchTimestamp(), + constantsHolder.BOUNTY_LOCKUP_MONTHS() + ), + "Bounty is locked" + ); uint256 bounty; uint256 endMonth; - (bounty, endMonth) = getAndUpdateEarnedBountyAmountOf(msg.sender, validatorId); + (bounty, endMonth) = getAndUpdateEarnedBountyAmountOf( + msg.sender, + validatorId + ); _firstUnwithdrawnMonth[msg.sender][validatorId] = endMonth; IERC20 skaleToken = IERC20(contractManager.getContract("SkaleToken")); require(skaleToken.transfer(to, bounty), "Failed to transfer tokens"); - emit WithdrawBounty( - msg.sender, - validatorId, - to, - bounty - ); + emit WithdrawBounty(msg.sender, validatorId, to, bounty); } /** @@ -120,15 +130,25 @@ contract Distributor is Permissions, IERC777Recipient, IDistributor { * - Fee must be unlocked. */ function withdrawFee(address to) external override { - IValidatorService validatorService = IValidatorService(contractManager.getContract("ValidatorService")); + IValidatorService validatorService = IValidatorService( + contractManager.getContract("ValidatorService") + ); IERC20 skaleToken = IERC20(contractManager.getContract("SkaleToken")); - ITimeHelpers timeHelpers = ITimeHelpers(contractManager.getContract("TimeHelpers")); - ConstantsHolder constantsHolder = ConstantsHolder(contractManager.getContract("ConstantsHolder")); + ITimeHelpers timeHelpers = ITimeHelpers( + contractManager.getContract("TimeHelpers") + ); + ConstantsHolder constantsHolder = ConstantsHolder( + contractManager.getContract("ConstantsHolder") + ); - require(block.timestamp >= timeHelpers.addMonths( - constantsHolder.launchTimestamp(), - constantsHolder.BOUNTY_LOCKUP_MONTHS() - ), "Fee is locked"); + require( + block.timestamp >= + timeHelpers.addMonths( + constantsHolder.launchTimestamp(), + constantsHolder.BOUNTY_LOCKUP_MONTHS() + ), + "Fee is locked" + ); // check Validator Exist inside getValidatorId uint256 validatorId = validatorService.getValidatorId(msg.sender); @@ -140,11 +160,7 @@ contract Distributor is Permissions, IERC777Recipient, IDistributor { require(skaleToken.transfer(to, fee), "Failed to transfer tokens"); - emit WithdrawFee( - validatorId, - to, - fee - ); + emit WithdrawFee(validatorId, to, fee); } function tokensReceived( @@ -154,11 +170,7 @@ contract Distributor is Permissions, IERC777Recipient, IDistributor { uint256 amount, bytes calldata userData, bytes calldata - ) - external - override - allow("SkaleToken") - { + ) external override allow("SkaleToken") { require(to == address(this), "Receiver is incorrect"); require(userData.length == 32, "Data length is incorrect"); uint256 validatorId = abi.decode(userData, (uint256)); @@ -168,28 +180,41 @@ contract Distributor is Permissions, IERC777Recipient, IDistributor { /** * @dev Return the amount of earned validator fees of `msg.sender`. */ - function getEarnedFeeAmount() external view override returns (uint256 earned, uint256 endMonth) { - IValidatorService validatorService = IValidatorService(contractManager.getContract("ValidatorService")); - return getEarnedFeeAmountOf(validatorService.getValidatorId(msg.sender)); + function getEarnedFeeAmount() + external + view + override + returns (uint256 earned, uint256 endMonth) + { + IValidatorService validatorService = IValidatorService( + contractManager.getContract("ValidatorService") + ); + return + getEarnedFeeAmountOf(validatorService.getValidatorId(msg.sender)); } /** * @dev Return and update the amount of earned bounties. */ - function getAndUpdateEarnedBountyAmountOf(address wallet, uint256 validatorId) - public - override - returns (uint256 earned, uint256 endMonth) - { + function getAndUpdateEarnedBountyAmountOf( + address wallet, + uint256 validatorId + ) public override returns (uint256 earned, uint256 endMonth) { IDelegationController delegationController = IDelegationController( - contractManager.getContract("DelegationController")); - ITimeHelpers timeHelpers = ITimeHelpers(contractManager.getContract("TimeHelpers")); + contractManager.getContract("DelegationController") + ); + ITimeHelpers timeHelpers = ITimeHelpers( + contractManager.getContract("TimeHelpers") + ); uint256 currentMonth = timeHelpers.getCurrentMonth(); uint256 startMonth = _firstUnwithdrawnMonth[wallet][validatorId]; if (startMonth == 0) { - startMonth = delegationController.getFirstDelegationMonth(wallet, validatorId); + startMonth = delegationController.getFirstDelegationMonth( + wallet, + validatorId + ); if (startMonth == 0) { return (0, 0); } @@ -201,12 +226,18 @@ contract Distributor is Permissions, IERC777Recipient, IDistributor { endMonth = startMonth + 12; } for (uint256 i = startMonth; i < endMonth; ++i) { - uint256 effectiveDelegatedToValidator = - delegationController.getAndUpdateEffectiveDelegatedToValidator(validatorId, i); + uint256 effectiveDelegatedToValidator = delegationController + .getAndUpdateEffectiveDelegatedToValidator(validatorId, i); if (effectiveDelegatedToValidator.muchGreater(0)) { - earned = earned + - _bountyPaid[validatorId][i] * - delegationController.getAndUpdateEffectiveDelegatedByHolderToValidator(wallet, validatorId, i) / + earned = + earned + + (_bountyPaid[validatorId][i] * + delegationController + .getAndUpdateEffectiveDelegatedByHolderToValidator( + wallet, + validatorId, + i + )) / effectiveDelegatedToValidator; } } @@ -215,8 +246,12 @@ contract Distributor is Permissions, IERC777Recipient, IDistributor { /** * @dev Return the amount of earned fees by validator ID. */ - function getEarnedFeeAmountOf(uint256 validatorId) public view override returns (uint256 earned, uint256 endMonth) { - ITimeHelpers timeHelpers = ITimeHelpers(contractManager.getContract("TimeHelpers")); + function getEarnedFeeAmountOf( + uint256 validatorId + ) public view override returns (uint256 earned, uint256 endMonth) { + ITimeHelpers timeHelpers = ITimeHelpers( + contractManager.getContract("TimeHelpers") + ); uint256 currentMonth = timeHelpers.getCurrentMonth(); @@ -243,16 +278,24 @@ contract Distributor is Permissions, IERC777Recipient, IDistributor { * Emits a {BountyWasPaid} event. */ function _distributeBounty(uint256 amount, uint256 validatorId) private { - ITimeHelpers timeHelpers = ITimeHelpers(contractManager.getContract("TimeHelpers")); - IValidatorService validatorService = IValidatorService(contractManager.getContract("ValidatorService")); + ITimeHelpers timeHelpers = ITimeHelpers( + contractManager.getContract("TimeHelpers") + ); + IValidatorService validatorService = IValidatorService( + contractManager.getContract("ValidatorService") + ); uint256 currentMonth = timeHelpers.getCurrentMonth(); uint256 feeRate = validatorService.getValidator(validatorId).feeRate; - uint256 fee = amount * feeRate / 1000; + uint256 fee = (amount * feeRate) / 1000; uint256 bounty = amount - fee; - _bountyPaid[validatorId][currentMonth] = _bountyPaid[validatorId][currentMonth] + bounty; - _feePaid[validatorId][currentMonth] = _feePaid[validatorId][currentMonth] + fee; + _bountyPaid[validatorId][currentMonth] = + _bountyPaid[validatorId][currentMonth] + + bounty; + _feePaid[validatorId][currentMonth] = + _feePaid[validatorId][currentMonth] + + fee; if (_firstUnwithdrawnMonthForValidator[validatorId] == 0) { _firstUnwithdrawnMonthForValidator[validatorId] = currentMonth; diff --git a/contracts/delegation/PartialDifferences.sol b/contracts/delegation/PartialDifferences.sol index e07fffabc..a6947e3b6 100644 --- a/contracts/delegation/PartialDifferences.sol +++ b/contracts/delegation/PartialDifferences.sol @@ -21,8 +21,8 @@ pragma solidity 0.8.17; -import { MathUtils } from "../utils/MathUtils.sol"; -import { FractionUtils } from "../utils/FractionUtils.sol"; +import {MathUtils} from "../utils/MathUtils.sol"; +import {FractionUtils} from "../utils/FractionUtils.sol"; /** * @title Partial Differences Library @@ -44,23 +44,21 @@ 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; - + // 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; - + // month => diff + mapping(uint256 => uint256) addDiff; + // month => diff + mapping(uint256 => uint256) subtractDiff; uint256 value; uint256 firstUnprocessedMonth; uint256 lastChangedMonth; @@ -68,8 +66,15 @@ library PartialDifferences { // functions for sequence - function addToSequence(Sequence storage sequence, uint256 diff, uint256 month) internal { - require(sequence.firstUnprocessedMonth <= month, "Cannot add to the past"); + 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; } @@ -79,8 +84,15 @@ library PartialDifferences { } } - function subtractFromSequence(Sequence storage sequence, uint256 diff, uint256 month) internal { - require(sequence.firstUnprocessedMonth <= month, "Cannot subtract from the past"); + 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; } @@ -90,14 +102,18 @@ library PartialDifferences { } } - function getAndUpdateValueInSequence(Sequence storage sequence, uint256 month) internal returns (uint256 value) { + 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]); + uint256 nextValue = (sequence.value[i - 1] + + sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]); if (sequence.value[i] != nextValue) { sequence.value[i] = nextValue; } @@ -117,12 +133,16 @@ library PartialDifferences { function reduceSequence( Sequence storage sequence, FractionUtils.Fraction memory reducingCoefficient, - uint256 month) internal - { - require(month + 1 >= sequence.firstUnprocessedMonth, "Cannot reduce value in the past"); + 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"); + "Increasing of values is not implemented" + ); if (sequence.firstUnprocessedMonth == 0) { return; } @@ -131,21 +151,28 @@ library PartialDifferences { return; } - sequence.value[month] = sequence.value[month] - * reducingCoefficient.numerator - / reducingCoefficient.denominator; + 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; + 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"); + 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; @@ -161,8 +188,15 @@ library PartialDifferences { } } - function subtractFromValue(Value storage sequence, uint256 diff, uint256 month) internal { - require(sequence.firstUnprocessedMonth <= month + 1, "Cannot subtract from the past"); + 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; @@ -178,10 +212,14 @@ library PartialDifferences { } } - function getAndUpdateValue(Value storage sequence, uint256 month) internal returns (uint256 value) { + function getAndUpdateValue( + Value storage sequence, + uint256 month + ) internal returns (uint256 value) { require( month + 1 >= sequence.firstUnprocessedMonth, - "Cannot calculate value in the past"); + "Cannot calculate value in the past" + ); if (sequence.firstUnprocessedMonth == 0) { return 0; } @@ -189,7 +227,9 @@ library PartialDifferences { if (sequence.firstUnprocessedMonth <= month) { value = sequence.value; for (uint256 i = sequence.firstUnprocessedMonth; i <= month; ++i) { - value = (value + sequence.addDiff[i]).boundedSub(sequence.subtractDiff[i]); + value = (value + sequence.addDiff[i]).boundedSub( + sequence.subtractDiff[i] + ); if (sequence.addDiff[i] > 0) { delete sequence.addDiff[i]; } @@ -209,10 +249,12 @@ library PartialDifferences { 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"); + 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); } @@ -226,8 +268,10 @@ library PartialDifferences { _amount = value; } - reducingCoefficient = - FractionUtils.createFraction(value.boundedSub(_amount), value); + reducingCoefficient = FractionUtils.createFraction( + value.boundedSub(_amount), + value + ); reduceValueByCoefficient(sequence, reducingCoefficient, month); return reducingCoefficient; } @@ -235,9 +279,8 @@ library PartialDifferences { function reduceValueByCoefficient( Value storage sequence, FractionUtils.Fraction memory reducingCoefficient, - uint256 month) - internal - { + uint256 month + ) internal { reduceValueByCoefficientAndUpdateSumIfNeeded({ sequence: sequence, sumSequence: sequence, @@ -251,8 +294,8 @@ library PartialDifferences { Value storage sequence, Value storage sumSequence, FractionUtils.Fraction memory reducingCoefficient, - uint256 month) internal - { + uint256 month + ) internal { reduceValueByCoefficientAndUpdateSumIfNeeded({ sequence: sequence, sumSequence: sumSequence, @@ -267,15 +310,22 @@ library PartialDifferences { Value storage sumSequence, FractionUtils.Fraction memory reducingCoefficient, uint256 month, - bool hasSumSequence) internal - { - require(month + 1 >= sequence.firstUnprocessedMonth, "Cannot reduce value in the past"); + 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( + month + 1 >= sumSequence.firstUnprocessedMonth, + "Cannot reduce value in the past" + ); } require( reducingCoefficient.numerator <= reducingCoefficient.denominator, - "Increasing of values is not implemented"); + "Increasing of values is not implemented" + ); if (sequence.firstUnprocessedMonth == 0) { return; } @@ -284,25 +334,34 @@ library PartialDifferences { return; } - uint256 newValue = sequence.value * reducingCoefficient.numerator / reducingCoefficient.denominator; + uint256 newValue = (sequence.value * reducingCoefficient.numerator) / + reducingCoefficient.denominator; if (hasSumSequence) { - subtractFromValue(sumSequence, sequence.value.boundedSub(newValue), month); + 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; + uint256 newDiff = (sequence.subtractDiff[i] * + reducingCoefficient.numerator) / + reducingCoefficient.denominator; if (hasSumSequence) { - sumSequence.subtractDiff[i] = sumSequence.subtractDiff[i] + 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) { + function getValueInSequence( + Sequence storage sequence, + uint256 month + ) internal view returns (uint256 value) { if (sequence.firstUnprocessedMonth == 0) { return 0; } @@ -318,7 +377,9 @@ library PartialDifferences { } } - function getValuesInSequence(Sequence storage sequence) internal view returns (uint256[] memory values) { + function getValuesInSequence( + Sequence storage sequence + ) internal view returns (uint256[] memory values) { if (sequence.firstUnprocessedMonth == 0) { return values; } @@ -331,14 +392,21 @@ library PartialDifferences { 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]; + values[i + 1] = + values[i] + + sequence.addDiff[month] - + sequence.subtractDiff[month]; } } - function getValue(Value storage sequence, uint256 month) internal view returns (uint256 value) { + function getValue( + Value storage sequence, + uint256 month + ) internal view returns (uint256 value) { require( month + 1 >= sequence.firstUnprocessedMonth, - "Cannot calculate value in the past"); + "Cannot calculate value in the past" + ); if (sequence.firstUnprocessedMonth == 0) { return 0; } @@ -354,7 +422,9 @@ library PartialDifferences { } } - function getValues(Value storage sequence) internal view returns (uint256[] memory values) { + function getValues( + Value storage sequence + ) internal view returns (uint256[] memory values) { if (sequence.firstUnprocessedMonth == 0) { return values; } @@ -367,7 +437,10 @@ library PartialDifferences { 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]; + values[i + 1] = + values[i] + + sequence.addDiff[month] - + sequence.subtractDiff[month]; } } } diff --git a/contracts/delegation/Punisher.sol b/contracts/delegation/Punisher.sol index 94ffd436a..5f506f0ce 100644 --- a/contracts/delegation/Punisher.sol +++ b/contracts/delegation/Punisher.sol @@ -21,24 +21,29 @@ pragma solidity 0.8.17; -import { IPunisher } from "@skalenetwork/skale-manager-interfaces/delegation/IPunisher.sol"; -import { ILocker } from "@skalenetwork/skale-manager-interfaces/delegation/ILocker.sol"; -import { IValidatorService } from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; -import { IDelegationController } from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; +import {IPunisher} from "@skalenetwork/skale-manager-interfaces/delegation/IPunisher.sol"; +import {ILocker} from "@skalenetwork/skale-manager-interfaces/delegation/ILocker.sol"; +import { + IValidatorService +} from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; +import { + IDelegationController +} from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; -import { Permissions } from "../Permissions.sol"; +import {Permissions} from "../Permissions.sol"; /** * @title Punisher * @dev This contract handles all slashing and forgiving operations. */ contract Punisher is Permissions, ILocker, IPunisher { - // holder => tokens - mapping (address => uint256) private _locked; + mapping(address => uint256) private _locked; bytes32 public constant FORGIVER_ROLE = keccak256("FORGIVER_ROLE"); - function initialize(address contractManagerAddress) public override initializer { + function initialize( + address contractManagerAddress + ) public override initializer { Permissions.initialize(contractManagerAddress); } @@ -52,12 +57,21 @@ contract Punisher is Permissions, ILocker, IPunisher { * * - Validator must exist. */ - function slash(uint256 validatorId, uint256 amount) external override allow("SkaleDKG") { - IValidatorService validatorService = IValidatorService(contractManager.getContract("ValidatorService")); + function slash( + uint256 validatorId, + uint256 amount + ) external override allow("SkaleDKG") { + IValidatorService validatorService = IValidatorService( + contractManager.getContract("ValidatorService") + ); IDelegationController delegationController = IDelegationController( - contractManager.getContract("DelegationController")); + contractManager.getContract("DelegationController") + ); - require(validatorService.validatorExists(validatorId), "Validator does not exist"); + require( + validatorService.validatorExists(validatorId), + "Validator does not exist" + ); delegationController.confiscate(validatorId, amount); @@ -74,11 +88,18 @@ contract Punisher is Permissions, ILocker, IPunisher { * - All slashes must have been processed. */ function forgive(address holder, uint256 amount) external override { - require(hasRole(FORGIVER_ROLE, msg.sender), "FORGIVER_ROLE is required"); + require( + hasRole(FORGIVER_ROLE, msg.sender), + "FORGIVER_ROLE is required" + ); IDelegationController delegationController = IDelegationController( - contractManager.getContract("DelegationController")); + contractManager.getContract("DelegationController") + ); - require(!delegationController.hasUnprocessedSlashes(holder), "Not all slashes were calculated"); + require( + !delegationController.hasUnprocessedSlashes(holder), + "Not all slashes were calculated" + ); if (amount > _locked[holder]) { delete _locked[holder]; @@ -92,14 +113,18 @@ contract Punisher is Permissions, ILocker, IPunisher { /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ - function getAndUpdateLockedAmount(address wallet) external override returns (uint256 amount) { + 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) { + function getAndUpdateForbiddenForDelegationAmount( + address wallet + ) external override returns (uint256 amount) { return _getAndUpdateLockedAmount(wallet); } @@ -107,7 +132,10 @@ contract Punisher is Permissions, ILocker, IPunisher { * @dev Allows DelegationController contract to execute slashing of * delegations. */ - function handleSlash(address holder, uint256 amount) external override allow("DelegationController") { + function handleSlash( + address holder, + uint256 amount + ) external override allow("DelegationController") { _locked[holder] = _locked[holder] + amount; } @@ -116,12 +144,14 @@ contract Punisher is Permissions, ILocker, IPunisher { /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ - function _getAndUpdateLockedAmount(address wallet) private returns (uint256 amount) { + function _getAndUpdateLockedAmount( + address wallet + ) private returns (uint256 amount) { IDelegationController delegationController = IDelegationController( - contractManager.getContract("DelegationController")); + contractManager.getContract("DelegationController") + ); delegationController.processAllSlashes(wallet); return _locked[wallet]; } - } diff --git a/contracts/delegation/TimeHelpers.sol b/contracts/delegation/TimeHelpers.sol index b3f217ba9..82635738e 100644 --- a/contracts/delegation/TimeHelpers.sol +++ b/contracts/delegation/TimeHelpers.sol @@ -21,9 +21,9 @@ pragma solidity 0.8.17; -import { ITimeHelpers } from "@skalenetwork/skale-manager-interfaces/delegation/ITimeHelpers.sol"; +import {ITimeHelpers} from "@skalenetwork/skale-manager-interfaces/delegation/ITimeHelpers.sol"; -import { BokkyPooBahsDateTimeLibrary } from "../thirdparty/BokkyPooBahsDateTimeLibrary.sol"; +import {BokkyPooBahsDateTimeLibrary} from "../thirdparty/BokkyPooBahsDateTimeLibrary.sol"; /** * @title TimeHelpers @@ -32,50 +32,78 @@ import { BokkyPooBahsDateTimeLibrary } from "../thirdparty/BokkyPooBahsDateTimeL * These functions are used to calculate monthly and Proof of Use epochs. */ contract TimeHelpers is ITimeHelpers { + uint256 private constant _ZERO_YEAR = 2020; + + function calculateProofOfUseLockEndTime( + uint256 month, + uint256 lockUpPeriodDays + ) external view override returns (uint256 timestamp) { + timestamp = BokkyPooBahsDateTimeLibrary.addDays( + monthToTimestamp(month), + lockUpPeriodDays + ); + } - uint256 constant private _ZERO_YEAR = 2020; - - function calculateProofOfUseLockEndTime(uint256 month, uint256 lockUpPeriodDays) + function getCurrentMonth() external view + virtual override - returns (uint256 timestamp) + returns (uint256 month) { - timestamp = BokkyPooBahsDateTimeLibrary.addDays(monthToTimestamp(month), lockUpPeriodDays); - } - - function getCurrentMonth() external view virtual override returns (uint256 month) { return timestampToMonth(block.timestamp); } - function timestampToYear(uint256 timestamp) external view virtual override returns (uint256 year) { - (year, , ) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); + function timestampToYear( + uint256 timestamp + ) external view virtual override returns (uint256 year) { + uint256 month; + uint256 day; + (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate( + timestamp + ); require(year >= _ZERO_YEAR, "Timestamp is too far in the past"); return year - _ZERO_YEAR; } - function addDays(uint256 fromTimestamp, uint256 n) external pure override returns (uint256 result) { + function addDays( + uint256 fromTimestamp, + uint256 n + ) external pure override returns (uint256 result) { return BokkyPooBahsDateTimeLibrary.addDays(fromTimestamp, n); } - function addMonths(uint256 fromTimestamp, uint256 n) external pure override returns (uint256 result) { + function addMonths( + uint256 fromTimestamp, + uint256 n + ) external pure override returns (uint256 result) { return BokkyPooBahsDateTimeLibrary.addMonths(fromTimestamp, n); } - function addYears(uint256 fromTimestamp, uint256 n) external pure override returns (uint256 result) { + function addYears( + uint256 fromTimestamp, + uint256 n + ) external pure override returns (uint256 result) { return BokkyPooBahsDateTimeLibrary.addYears(fromTimestamp, n); } - function timestampToMonth(uint256 timestamp) public view virtual override returns (uint256 month) { + function timestampToMonth( + uint256 timestamp + ) public view virtual override returns (uint256 month) { uint256 year; - (year, month, ) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); + uint256 day; + (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate( + timestamp + ); require(year >= _ZERO_YEAR, "Timestamp is too far in the past"); month = month - 1 + (year - _ZERO_YEAR) * 12; require(month > 0, "Timestamp is too far in the past"); return month; } - function monthToTimestamp(uint256 month) public view virtual override returns (uint256 timestamp) { + function monthToTimestamp( + uint256 month + ) public view virtual override returns (uint256 timestamp) { uint256 year = _ZERO_YEAR; uint256 _month = month; year = year + _month / 12; diff --git a/contracts/delegation/TokenState.sol b/contracts/delegation/TokenState.sol index 9c0f09cc9..e2c889534 100644 --- a/contracts/delegation/TokenState.sol +++ b/contracts/delegation/TokenState.sol @@ -21,12 +21,13 @@ pragma solidity 0.8.17; -import { ITokenState } from "@skalenetwork/skale-manager-interfaces/delegation/ITokenState.sol"; -import { ILocker } from "@skalenetwork/skale-manager-interfaces/delegation/ILocker.sol"; -import { IDelegationController } from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; - -import { Permissions } from "../Permissions.sol"; +import {ITokenState} from "@skalenetwork/skale-manager-interfaces/delegation/ITokenState.sol"; +import {ILocker} from "@skalenetwork/skale-manager-interfaces/delegation/ILocker.sol"; +import { + IDelegationController +} from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; +import {Permissions} from "../Permissions.sol"; /** * @title Token State @@ -45,19 +46,24 @@ import { Permissions } from "../Permissions.sol"; * `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"); + bytes32 public constant LOCKER_MANAGER_ROLE = + keccak256("LOCKER_MANAGER_ROLE"); modifier onlyLockerManager() { - require(hasRole(LOCKER_MANAGER_ROLE, msg.sender), "LOCKER_MANAGER_ROLE is required"); + require( + hasRole(LOCKER_MANAGER_ROLE, msg.sender), + "LOCKER_MANAGER_ROLE is required" + ); _; } - function initialize(address contractManagerAddress) public override initializer { + function initialize( + address contractManagerAddress + ) public override initializer { Permissions.initialize(contractManagerAddress); _setupRole(LOCKER_MANAGER_ROLE, msg.sender); addLocker("DelegationController"); @@ -67,16 +73,21 @@ contract TokenState is Permissions, ILocker, ITokenState { /** * @dev See {ILocker-getAndUpdateLockedAmount}. */ - function getAndUpdateLockedAmount(address holder) external override returns (uint256 amount) { + function getAndUpdateLockedAmount( + address holder + ) external override returns (uint256 amount) { if (address(_delegationController) == address(0)) { - _delegationController = - IDelegationController(contractManager.getContract("DelegationController")); + _delegationController = IDelegationController( + contractManager.getContract("DelegationController") + ); } uint256 locked = 0; if (_delegationController.getDelegationsByHolderLength(holder) > 0) { // the holder ever delegated for (uint256 i = 0; i < _lockers.length; ++i) { - ILocker locker = ILocker(contractManager.getContract(_lockers[i])); + ILocker locker = ILocker( + contractManager.getContract(_lockers[i]) + ); locked = locked + locker.getAndUpdateLockedAmount(holder); } } @@ -86,11 +97,15 @@ contract TokenState is Permissions, ILocker, ITokenState { /** * @dev See {ILocker-getAndUpdateForbiddenForDelegationAmount}. */ - function getAndUpdateForbiddenForDelegationAmount(address holder) external override returns (uint256 amount) { + function getAndUpdateForbiddenForDelegationAmount( + address holder + ) external override returns (uint256 amount) { uint256 forbidden = 0; for (uint256 i = 0; i < _lockers.length; ++i) { ILocker locker = ILocker(contractManager.getContract(_lockers[i])); - forbidden = forbidden + locker.getAndUpdateForbiddenForDelegationAmount(holder); + forbidden = + forbidden + + locker.getAndUpdateForbiddenForDelegationAmount(holder); } return forbidden; } @@ -100,19 +115,22 @@ contract TokenState is Permissions, ILocker, ITokenState { * * Emits a {LockerWasRemoved} event. */ - function removeLocker(string calldata locker) external override onlyLockerManager { + function removeLocker( + string calldata locker + ) external override onlyLockerManager { uint256 index; + uint256 lockersLength = _lockers.length; bytes32 hash = keccak256(abi.encodePacked(locker)); - for (index = 0; index < _lockers.length; ++index) { + for (index = 0; index < lockersLength; ++index) { if (keccak256(abi.encodePacked(_lockers[index])) == hash) { break; } } - if (index < _lockers.length) { - if (index < _lockers.length - 1) { - _lockers[index] = _lockers[_lockers.length - 1]; + if (index < lockersLength) { + if (index < lockersLength - 1) { + _lockers[index] = _lockers[lockersLength - 1]; } - delete _lockers[_lockers.length - 1]; + delete _lockers[lockersLength - 1]; _lockers.pop(); emit LockerWasRemoved(locker); } diff --git a/contracts/delegation/ValidatorService.sol b/contracts/delegation/ValidatorService.sol index 3bf6ce6c6..bd1a002c3 100644 --- a/contracts/delegation/ValidatorService.sol +++ b/contracts/delegation/ValidatorService.sol @@ -21,14 +21,53 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; - -import { ECDSAUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; - -import { IValidatorService } from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; -import { IDelegationController } from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; - -import { Permissions } from "../Permissions.sol"; +pragma solidity 0.8.26; + +import { + ECDSAUpgradeable +} from "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol"; +import { + IValidatorService +} from "@skalenetwork/skale-manager-interfaces/delegation/IValidatorService.sol"; +import { + IDelegationController +} from "@skalenetwork/skale-manager-interfaces/delegation/IDelegationController.sol"; +import { + IPaymasterController +} from "@skalenetwork/skale-manager-interfaces/IPaymasterController.sol"; + +import {AddressIsNotSet, RoleRequired} from "../CommonErrors.sol"; +import {Permissions} from "../Permissions.sol"; + + +error ValidatorDoesNotExist(uint256 id); +error AddressIsAlreadyInUse(address validatorAddress); +error WrongFeeValue(uint256 value); +error ValidatorIsAlreadyEnabled(uint256 validatorId); +error ValidatorIsAlreadyDisabled(uint256 validatorId); +error SenderHasToBeEqualToRequestedAddress( + address sender, + address requestedAddress +); +error WrongSignature(); +error NodeAddressIsAValidator(address nodeAddress, uint256 validatorId); +error AcceptingRequestIsAlreadyEnabled(uint256 validatorId); +error AcceptingRequestIsAlreadyDisabled(uint256 validatorId); +error NoPermissionsToUnlinkNode(uint256 validatorId, address nodeAddress); +error NodeAddressIsNotAssignedToValidator(address nodeAddress); +error ValidatorIsNotAuthorized( + uint256 validatorId +); +error ValidatorIsNotCurrentlyAcceptingNewRequests(uint256 validatorId); +error AmountDoesNotMeetTheValidatorsMinimumDelegationAmount( + uint256 amount, + uint256 minimum +); +error ValidatorAddressDoesNotExist(address validatorAddress); +error ValidatorCannotOverrideNodeAddress( + uint256 validatorId, + address nodeAddress +); /** * @title ValidatorService @@ -42,34 +81,40 @@ import { Permissions } from "../Permissions.sol"; * register nodes. */ contract ValidatorService is Permissions, IValidatorService { - using ECDSAUpgradeable for bytes32; - mapping (uint256 => Validator) public validators; - mapping (uint256 => bool) private _trustedValidators; + mapping(uint256 => Validator) public validators; + mapping(uint256 => bool) private _trustedValidators; uint256[] public trustedValidatorsList; // address => validatorId - mapping (address => uint256) private _validatorAddressToId; + mapping(address => uint256) private _validatorAddressToId; // address => validatorId - mapping (address => uint256) private _nodeAddressToValidatorId; + mapping(address => uint256) private _nodeAddressToValidatorId; // validatorId => nodeAddress[] - mapping (uint256 => address[]) private _nodeAddresses; + mapping(uint256 => address[]) private _nodeAddresses; uint256 public numberOfValidators; bool public useWhitelist; - bytes32 public constant VALIDATOR_MANAGER_ROLE = keccak256("VALIDATOR_MANAGER_ROLE"); + bytes32 public constant VALIDATOR_MANAGER_ROLE = + keccak256("VALIDATOR_MANAGER_ROLE"); modifier onlyValidatorManager() { - require(hasRole(VALIDATOR_MANAGER_ROLE, msg.sender), "VALIDATOR_MANAGER_ROLE is required"); + if (!hasRole(VALIDATOR_MANAGER_ROLE, msg.sender)) { + revert RoleRequired(VALIDATOR_MANAGER_ROLE); + } _; } modifier checkValidatorExists(uint256 validatorId) { - require(validatorExists(validatorId), "Validator with such ID does not exist"); + if (!validatorExists(validatorId)) { + revert ValidatorDoesNotExist(validatorId); + } _; } - function initialize(address contractManagerAddress) public override initializer { + function initialize( + address contractManagerAddress + ) public override initializer { Permissions.initialize(contractManagerAddress); useWhitelist = true; } @@ -90,13 +135,13 @@ contract ValidatorService is Permissions, IValidatorService { string calldata description, uint256 feeRate, uint256 minimumDelegationAmount - ) - external - override - returns (uint256 validatorId) - { - require(!validatorAddressExists(msg.sender), "Validator with such address already exists"); - require(feeRate <= 1000, "Fee rate of validator should be lower than 100%"); + ) external override returns (uint256 validatorId) { + if (validatorAddressExists(msg.sender)) { + revert AddressIsAlreadyInUse(msg.sender); + } + if (1000 < feeRate) { + revert WrongFeeValue(feeRate); + } validatorId = ++numberOfValidators; validators[validatorId] = IValidatorService.Validator({ name: name, @@ -111,6 +156,11 @@ contract ValidatorService is Permissions, IValidatorService { _setValidatorAddress(validatorId, msg.sender); emit ValidatorRegistered(validatorId); + + IPaymasterController paymasterController = IPaymasterController( + contractManager.getContract("PaymasterController") + ); + paymasterController.addValidator(validatorId, msg.sender); } /** @@ -123,13 +173,12 @@ contract ValidatorService is Permissions, IValidatorService { * * - Validator must not already be enabled. */ - function enableValidator(uint256 validatorId) - external - override - checkValidatorExists(validatorId) - onlyValidatorManager - { - require(!_trustedValidators[validatorId], "Validator is already enabled"); + function enableValidator( + uint256 validatorId + ) external override checkValidatorExists(validatorId) onlyValidatorManager { + if (_trustedValidators[validatorId]) { + revert ValidatorIsAlreadyEnabled(validatorId); + } _trustedValidators[validatorId] = true; trustedValidatorsList.push(validatorId); emit ValidatorWasEnabled(validatorId); @@ -145,18 +194,18 @@ contract ValidatorService is Permissions, IValidatorService { * * - Validator must not already be disabled. */ - function disableValidator(uint256 validatorId) - external - override - checkValidatorExists(validatorId) - onlyValidatorManager - { - require(_trustedValidators[validatorId], "Validator is already disabled"); + function disableValidator( + uint256 validatorId + ) external override checkValidatorExists(validatorId) onlyValidatorManager { + if (!_trustedValidators[validatorId]) { + revert ValidatorIsAlreadyDisabled(validatorId); + } _trustedValidators[validatorId] = false; uint256 position = _find(trustedValidatorsList, validatorId); if (position < trustedValidatorsList.length) { - trustedValidatorsList[position] = - trustedValidatorsList[trustedValidatorsList.length - 1]; + trustedValidatorsList[position] = trustedValidatorsList[ + trustedValidatorsList.length - 1 + ]; } trustedValidatorsList.pop(); emit ValidatorWasDisabled(validatorId); @@ -180,9 +229,15 @@ contract ValidatorService is Permissions, IValidatorService { * - New address must not be null. * - New address must not be already registered as a validator. */ - function requestForNewAddress(address newValidatorAddress) external override { - require(newValidatorAddress != address(0), "New address cannot be null"); - require(_validatorAddressToId[newValidatorAddress] == 0, "Address already registered"); + function requestForNewAddress( + address newValidatorAddress + ) external override { + if (newValidatorAddress == address(0)) { + revert AddressIsNotSet(); + } + if (_validatorAddressToId[newValidatorAddress] != 0) { + revert AddressIsAlreadyInUse(newValidatorAddress); + } // check Validator Exist inside getValidatorId uint256 validatorId = getValidatorId(msg.sender); @@ -199,19 +254,27 @@ contract ValidatorService is Permissions, IValidatorService { * * - Must be owner of new address. */ - function confirmNewAddress(uint256 validatorId) - external - override - checkValidatorExists(validatorId) - { - require( - getValidator(validatorId).requestedAddress == msg.sender, - "The validator address cannot be changed because it is not the actual owner" - ); + function confirmNewAddress( + uint256 validatorId + ) external override checkValidatorExists(validatorId) { + if (getValidator(validatorId).requestedAddress != msg.sender) { + revert SenderHasToBeEqualToRequestedAddress( + msg.sender, + getValidator(validatorId).requestedAddress + ); + } delete validators[validatorId].requestedAddress; _setValidatorAddress(validatorId, msg.sender); - emit ValidatorAddressChanged(validatorId, validators[validatorId].validatorAddress); + emit ValidatorAddressChanged( + validatorId, + validators[validatorId].validatorAddress + ); + + IPaymasterController paymasterController = IPaymasterController( + contractManager.getContract("PaymasterController") + ); + paymasterController.setValidatorAddress(validatorId, msg.sender); } /** @@ -223,14 +286,25 @@ contract ValidatorService is Permissions, IValidatorService { * - Signature must be valid. * - Address must not be assigned to a validator. */ - function linkNodeAddress(address nodeAddress, bytes calldata sig) external override { + function linkNodeAddress( + address nodeAddress, + bytes calldata sig + ) external override { // check Validator Exist inside getValidatorId uint256 validatorId = getValidatorId(msg.sender); - require( - keccak256(abi.encodePacked(validatorId)).toEthSignedMessageHash().recover(sig) == nodeAddress, - "Signature is not pass" - ); - require(_validatorAddressToId[nodeAddress] == 0, "Node address is a validator"); + if ( + keccak256(abi.encodePacked(validatorId)) + .toEthSignedMessageHash() + .recover(sig) != nodeAddress + ) { + revert WrongSignature(); + } + if (_validatorAddressToId[nodeAddress] != 0) { + revert NodeAddressIsAValidator( + nodeAddress, + _validatorAddressToId[nodeAddress] + ); + } _addNodeAddress(validatorId, nodeAddress); emit NodeAddressWasAdded(validatorId, nodeAddress); @@ -252,7 +326,9 @@ contract ValidatorService is Permissions, IValidatorService { /** * @dev Allows a validator to set a minimum delegation amount. */ - function setValidatorMDA(uint256 minimumDelegationAmount) external override { + function setValidatorMDA( + uint256 minimumDelegationAmount + ) external override { // check Validator Exist inside getValidatorId uint256 validatorId = getValidatorId(msg.sender); @@ -261,7 +337,8 @@ contract ValidatorService is Permissions, IValidatorService { validators[validatorId].minimumDelegationAmount, minimumDelegationAmount ); - validators[validatorId].minimumDelegationAmount = minimumDelegationAmount; + validators[validatorId] + .minimumDelegationAmount = minimumDelegationAmount; } /** @@ -271,18 +348,28 @@ contract ValidatorService is Permissions, IValidatorService { // check Validator Exist inside getValidatorId uint256 validatorId = getValidatorId(msg.sender); - emit SetValidatorName(validatorId, validators[validatorId].name, newName); + emit SetValidatorName( + validatorId, + validators[validatorId].name, + newName + ); validators[validatorId].name = newName; } /** * @dev Allows a validator to set a new validator description. */ - function setValidatorDescription(string calldata newDescription) external override { + function setValidatorDescription( + string calldata newDescription + ) external override { // check Validator Exist inside getValidatorId uint256 validatorId = getValidatorId(msg.sender); - emit SetValidatorDescription(validatorId, validators[validatorId].description, newDescription); + emit SetValidatorDescription( + validatorId, + validators[validatorId].description, + newDescription + ); validators[validatorId].description = newDescription; } @@ -296,7 +383,9 @@ contract ValidatorService is Permissions, IValidatorService { function startAcceptingNewRequests() external override { // check Validator Exist inside getValidatorId uint256 validatorId = getValidatorId(msg.sender); - require(!isAcceptingNewRequests(validatorId), "Accepting request is already enabled"); + if (isAcceptingNewRequests(validatorId)) { + revert AcceptingRequestIsAlreadyEnabled(validatorId); + } validators[validatorId].acceptNewRequests = true; emit AcceptingNewRequests(validatorId, true); @@ -312,27 +401,32 @@ contract ValidatorService is Permissions, IValidatorService { function stopAcceptingNewRequests() external override { // check Validator Exist inside getValidatorId uint256 validatorId = getValidatorId(msg.sender); - require(isAcceptingNewRequests(validatorId), "Accepting request is already disabled"); + if (!isAcceptingNewRequests(validatorId)) { + revert AcceptingRequestIsAlreadyDisabled(validatorId); + } validators[validatorId].acceptNewRequests = false; emit AcceptingNewRequests(validatorId, false); } - function removeNodeAddress(uint256 validatorId, address nodeAddress) - external - override - allowTwo("ValidatorService", "Nodes") - { - require(_nodeAddressToValidatorId[nodeAddress] == validatorId, - "Validator does not have permissions to unlink node"); + function removeNodeAddress( + uint256 validatorId, + address nodeAddress + ) external override allowTwo("ValidatorService", "Nodes") { + if (_nodeAddressToValidatorId[nodeAddress] != validatorId) { + revert NoPermissionsToUnlinkNode(validatorId, nodeAddress); + } delete _nodeAddressToValidatorId[nodeAddress]; for (uint256 i = 0; i < _nodeAddresses[validatorId].length; ++i) { if (_nodeAddresses[validatorId][i] == nodeAddress) { if (i + 1 < _nodeAddresses[validatorId].length) { - _nodeAddresses[validatorId][i] = - _nodeAddresses[validatorId][_nodeAddresses[validatorId].length - 1]; + _nodeAddresses[validatorId][i] = _nodeAddresses[ + validatorId + ][_nodeAddresses[validatorId].length - 1]; } - delete _nodeAddresses[validatorId][_nodeAddresses[validatorId].length - 1]; + delete _nodeAddresses[validatorId][ + _nodeAddresses[validatorId].length - 1 + ]; _nodeAddresses[validatorId].pop(); break; } @@ -342,43 +436,50 @@ contract ValidatorService is Permissions, IValidatorService { /** * @dev Returns the amount of validator bond (self-delegation). */ - function getAndUpdateBondAmount(uint256 validatorId) - external - override - returns (uint256 bond) - { + function getAndUpdateBondAmount( + uint256 validatorId + ) external override returns (uint256 bond) { IDelegationController delegationController = IDelegationController( contractManager.getContract("DelegationController") ); - return delegationController.getAndUpdateDelegatedByHolderToValidatorNow( - getValidator(validatorId).validatorAddress, - validatorId - ); + return + delegationController.getAndUpdateDelegatedByHolderToValidatorNow( + getValidator(validatorId).validatorAddress, + validatorId + ); } /** * @dev Returns node addresses linked to the msg.sender. */ - function getMyNodesAddresses() external view override returns (address[] memory addresses) { + function getMyNodesAddresses() + external + view + override + returns (address[] memory addresses) + { return getNodeAddresses(getValidatorId(msg.sender)); } /** * @dev Returns the list of trusted validators. */ - function getTrustedValidators() external view override returns (uint256[] memory trustedValidators) { + function getTrustedValidators() + external + view + override + returns (uint256[] memory trustedValidators) + { return trustedValidatorsList; } /** * @dev Checks whether the validator ID is linked to the validator address. */ - function checkValidatorAddressToId(address validatorAddress, uint256 validatorId) - external - view - override - returns (bool valid) - { + function checkValidatorAddressToId( + address validatorAddress, + uint256 validatorId + ) external view override returns (bool valid) { return getValidatorId(validatorAddress) == validatorId ? true : false; } @@ -389,64 +490,88 @@ contract ValidatorService is Permissions, IValidatorService { * * - Node address must be linked to a validator. */ - function getValidatorIdByNodeAddress(address nodeAddress) external view override returns (uint256 validatorId) { + function getValidatorIdByNodeAddress( + address nodeAddress + ) external view override returns (uint256 validatorId) { validatorId = _nodeAddressToValidatorId[nodeAddress]; - require(validatorId != 0, "Node address is not assigned to a validator"); + if (validatorId == 0) { + revert NodeAddressIsNotAssignedToValidator(nodeAddress); + } } /** * @dev Returns the validator ID linked to a node address without revert. */ - function getValidatorIdByNodeAddressWithoutRevert(address nodeAddress) - external - view - override - returns (uint256 validatorId) - { + function getValidatorIdByNodeAddressWithoutRevert( + address nodeAddress + ) external view override returns (uint256 validatorId) { validatorId = _nodeAddressToValidatorId[nodeAddress]; } - function checkValidatorCanReceiveDelegation(uint256 validatorId, uint256 amount) external view override { - require(isAuthorizedValidator(validatorId), "Validator is not authorized to accept delegation request"); - require(isAcceptingNewRequests(validatorId), "The validator is not currently accepting new requests"); - require( - validators[validatorId].minimumDelegationAmount <= amount, - "Amount does not meet the validator's minimum delegation amount" - ); + function checkValidatorCanReceiveDelegation( + uint256 validatorId, + uint256 amount + ) external view override { + if (!isAuthorizedValidator(validatorId)) { + revert ValidatorIsNotAuthorized( + validatorId + ); + } + if (!isAcceptingNewRequests(validatorId)) { + revert ValidatorIsNotCurrentlyAcceptingNewRequests(validatorId); + } + if (amount < validators[validatorId].minimumDelegationAmount) { + revert AmountDoesNotMeetTheValidatorsMinimumDelegationAmount( + amount, + validators[validatorId].minimumDelegationAmount + ); + } } /** * @dev Returns a validator's node addresses. */ - function getNodeAddresses(uint256 validatorId) public view override returns (address[] memory nodeAddresses) { + function getNodeAddresses( + uint256 validatorId + ) public view override returns (address[] memory nodeAddresses) { return _nodeAddresses[validatorId]; } /** * @dev Checks whether validator ID exists. */ - function validatorExists(uint256 validatorId) public view override returns (bool exist) { + function validatorExists( + uint256 validatorId + ) public view override returns (bool exist) { return validatorId <= numberOfValidators && validatorId != 0; } /** * @dev Checks whether validator address exists. */ - function validatorAddressExists(address validatorAddress) public view override returns (bool exist) { + function validatorAddressExists( + address validatorAddress + ) public view override returns (bool exist) { return _validatorAddressToId[validatorAddress] != 0; } /** * @dev Checks whether validator address exists. */ - function checkIfValidatorAddressExists(address validatorAddress) public view override { - require(validatorAddressExists(validatorAddress), "Validator address does not exist"); + function checkIfValidatorAddressExists( + address validatorAddress + ) public view override { + if (!validatorAddressExists(validatorAddress)) { + revert ValidatorAddressDoesNotExist(validatorAddress); + } } /** * @dev Returns the Validator struct. */ - function getValidator(uint256 validatorId) + function getValidator( + uint256 validatorId + ) public view override @@ -459,7 +584,9 @@ contract ValidatorService is Permissions, IValidatorService { /** * @dev Returns the validator ID for the given validator address. */ - function getValidatorId(address validatorAddress) public view override returns (uint256 id) { + function getValidatorId( + address validatorAddress + ) public view override returns (uint256 id) { checkIfValidatorAddressExists(validatorAddress); return _validatorAddressToId[validatorAddress]; } @@ -467,7 +594,9 @@ contract ValidatorService is Permissions, IValidatorService { /** * @dev Checks whether the validator is currently accepting new delegation requests. */ - function isAcceptingNewRequests(uint256 validatorId) + function isAcceptingNewRequests( + uint256 validatorId + ) public view override @@ -477,7 +606,9 @@ contract ValidatorService is Permissions, IValidatorService { return validators[validatorId].acceptNewRequests; } - function isAuthorizedValidator(uint256 validatorId) + function isAuthorizedValidator( + uint256 validatorId + ) public view override @@ -496,11 +627,16 @@ contract ValidatorService is Permissions, IValidatorService { * * - Address is not already in use by another validator. */ - function _setValidatorAddress(uint256 validatorId, address validatorAddress) private { + function _setValidatorAddress( + uint256 validatorId, + address validatorAddress + ) private { if (_validatorAddressToId[validatorAddress] == validatorId) { return; } - require(_validatorAddressToId[validatorAddress] == 0, "Address is in use by another validator"); + if (_validatorAddressToId[validatorAddress] != 0) { + revert AddressIsAlreadyInUse(validatorAddress); + } address oldAddress = validators[validatorId].validatorAddress; delete _validatorAddressToId[oldAddress]; _nodeAddressToValidatorId[validatorAddress] = validatorId; @@ -519,12 +655,17 @@ contract ValidatorService is Permissions, IValidatorService { if (_nodeAddressToValidatorId[nodeAddress] == validatorId) { return; } - require(_nodeAddressToValidatorId[nodeAddress] == 0, "Validator cannot override node address"); + if (_nodeAddressToValidatorId[nodeAddress] != 0) { + revert ValidatorCannotOverrideNodeAddress(validatorId, nodeAddress); + } _nodeAddressToValidatorId[nodeAddress] = validatorId; _nodeAddresses[validatorId].push(nodeAddress); } - function _find(uint256[] memory array, uint256 value) private pure returns (uint256 index) { + function _find( + uint256[] memory array, + uint256 value + ) private pure returns (uint256 index) { for (index = 0; index < array.length; index++) { if (array[index] == value) { return index; diff --git a/contracts/dkg/SkaleDkgAlright.sol b/contracts/dkg/SkaleDkgAlright.sol index 12441181f..8c617af93 100644 --- a/contracts/dkg/SkaleDkgAlright.sol +++ b/contracts/dkg/SkaleDkgAlright.sol @@ -23,11 +23,12 @@ pragma solidity 0.8.17; -import { ISkaleDKG } from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; -import { IKeyStorage } from "@skalenetwork/skale-manager-interfaces/IKeyStorage.sol"; -import { IContractManager } from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; -import { IConstantsHolder } from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; +import {ISkaleDKG} from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; +import {IKeyStorage} from "@skalenetwork/skale-manager-interfaces/IKeyStorage.sol"; +import {IContractManager} from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; +import {IConstantsHolder} from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; +import {GroupIndexIsInvalid} from "../CommonErrors.sol"; /** * @title SkaleDkgAlright @@ -35,7 +36,6 @@ import { IConstantsHolder } from "@skalenetwork/skale-manager-interfaces/IConsta * Joint-Feldman protocol. */ library SkaleDkgAlright { - event AllDataReceived(bytes32 indexed schainHash, uint256 nodeIndex); event SuccessfulDKG(bytes32 indexed schainHash); @@ -48,37 +48,54 @@ library SkaleDkgAlright { mapping(bytes32 => ISkaleDKG.ComplaintData) storage complaints, mapping(bytes32 => uint256) storage lastSuccessfulDKG, mapping(bytes32 => uint256) storage startAlrightTimestamp - - ) - external - { + ) external { ISkaleDKG skaleDKG = ISkaleDKG(contractManager.getContract("SkaleDKG")); - (uint256 index, ) = skaleDKG.checkAndReturnIndexInGroup(schainHash, fromNodeIndex, true); + (uint256 index, bool valid) = skaleDKG.checkAndReturnIndexInGroup( + schainHash, + fromNodeIndex, + true + ); + if (!valid) { + revert GroupIndexIsInvalid(index); + } uint256 numberOfParticipant = channels[schainHash].n; - require(numberOfParticipant == dkgProcess[schainHash].numberOfBroadcasted, "Still Broadcasting phase"); require( - startAlrightTimestamp[schainHash] + _getComplaintTimeLimit(contractManager) > block.timestamp, + numberOfParticipant == dkgProcess[schainHash].numberOfBroadcasted, + "Still Broadcasting phase" + ); + require( + startAlrightTimestamp[schainHash] + + _getComplaintTimeLimit(contractManager) > + block.timestamp, "Incorrect time for alright" ); require( complaints[schainHash].fromNodeToComplaint != fromNodeIndex || - (fromNodeIndex == 0 && complaints[schainHash].startComplaintBlockTimestamp == 0), + (fromNodeIndex == 0 && + complaints[schainHash].startComplaintBlockTimestamp == 0), "Node has already sent complaint" ); - require(!dkgProcess[schainHash].completed[index], "Node is already alright"); + require( + !dkgProcess[schainHash].completed[index], + "Node is already alright" + ); dkgProcess[schainHash].completed[index] = true; dkgProcess[schainHash].numberOfCompleted++; emit AllDataReceived(schainHash, fromNodeIndex); if (dkgProcess[schainHash].numberOfCompleted == numberOfParticipant) { lastSuccessfulDKG[schainHash] = block.timestamp; channels[schainHash].active = false; - IKeyStorage(contractManager.getContract("KeyStorage")).finalizePublicKey(schainHash); + IKeyStorage(contractManager.getContract("KeyStorage")) + .finalizePublicKey(schainHash); emit SuccessfulDKG(schainHash); } } - function _getComplaintTimeLimit(IContractManager contractManager) private view returns (uint256 timeLimit) { - return IConstantsHolder(contractManager.getConstantsHolder()).complaintTimeLimit(); + function _getComplaintTimeLimit( + IContractManager contractManager + ) private view returns (uint256 timeLimit) { + return + IConstantsHolder(contractManager.getConstantsHolder()) + .complaintTimeLimit(); } - } diff --git a/contracts/dkg/SkaleDkgBroadcast.sol b/contracts/dkg/SkaleDkgBroadcast.sol index c598f17e6..194f25864 100644 --- a/contracts/dkg/SkaleDkgBroadcast.sol +++ b/contracts/dkg/SkaleDkgBroadcast.sol @@ -23,12 +23,13 @@ pragma solidity 0.8.17; -import { ISkaleDKG } from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; -import { IKeyStorage } from "@skalenetwork/skale-manager-interfaces/IKeyStorage.sol"; -import { IContractManager } from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; -import { IConstantsHolder } from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; -import { INodeRotation } from "@skalenetwork/skale-manager-interfaces/INodeRotation.sol"; +import {ISkaleDKG} from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; +import {IKeyStorage} from "@skalenetwork/skale-manager-interfaces/IKeyStorage.sol"; +import {IContractManager} from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; +import {IConstantsHolder} from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; +import {INodeRotation} from "@skalenetwork/skale-manager-interfaces/INodeRotation.sol"; +import {GroupIndexIsInvalid} from "../CommonErrors.sol"; /** * @title SkaleDkgBroadcast @@ -36,7 +37,6 @@ import { INodeRotation } from "@skalenetwork/skale-manager-interfaces/INodeRotat * Joint-Feldman protocol. */ library SkaleDkgBroadcast { - /** * @dev Emitted when a node broadcasts key share. */ @@ -47,7 +47,6 @@ library SkaleDkgBroadcast { ISkaleDKG.KeyShare[] secretKeyContribution ); - /** * @dev Broadcasts verification vector and secret key contribution to all * other nodes in the group. @@ -70,36 +69,40 @@ library SkaleDkgBroadcast { mapping(bytes32 => ISkaleDKG.ProcessDKG) storage dkgProcess, mapping(bytes32 => mapping(uint256 => bytes32)) storage hashedData, uint256 rotationCounter - ) - external - { + ) external { uint256 n = channels[schainHash].n; uint256 schainRotationCounter = INodeRotation( contractManager.getContract("NodeRotation") ).getRotation(schainHash).rotationCounter; require(schainRotationCounter == rotationCounter, "Incorrect rotation counter"); require(verificationVector.length == getT(n), "Incorrect number of verification vectors"); + require(secretKeyContribution.length == n, "Incorrect number of secret key shares"); require( - secretKeyContribution.length == n, - "Incorrect number of secret key shares" - ); - require( - channels[schainHash].startedBlockTimestamp + _getComplaintTimeLimit(contractManager) > block.timestamp, + channels[schainHash].startedBlockTimestamp + + _getComplaintTimeLimit(contractManager) > + block.timestamp, "Incorrect time for broadcast" ); - (uint256 index, ) = ISkaleDKG(contractManager.getContract("SkaleDKG")).checkAndReturnIndexInGroup( - schainHash, nodeIndex, true - ); + (uint256 index, bool valid) = ISkaleDKG( + contractManager.getContract("SkaleDKG") + ).checkAndReturnIndexInGroup(schainHash, nodeIndex, true); + if (!valid) { + revert GroupIndexIsInvalid(index); + } require(!dkgProcess[schainHash].broadcasted[index], "This node has already broadcasted"); dkgProcess[schainHash].broadcasted[index] = true; dkgProcess[schainHash].numberOfBroadcasted++; - if (dkgProcess[schainHash].numberOfBroadcasted == channels[schainHash].n) { - ISkaleDKG(contractManager.getContract("SkaleDKG")).setStartAlrightTimestamp(schainHash); + if ( dkgProcess[schainHash].numberOfBroadcasted == channels[schainHash].n ) { + ISkaleDKG(contractManager.getContract("SkaleDKG")) + .setStartAlrightTimestamp(schainHash); } - hashedData[schainHash][index] = ISkaleDKG(contractManager.getContract("SkaleDKG")).hashData( - secretKeyContribution, verificationVector + hashedData[schainHash][index] = ISkaleDKG( + contractManager.getContract("SkaleDKG") + ).hashData(secretKeyContribution, verificationVector); + IKeyStorage(contractManager.getContract("KeyStorage")).adding( + schainHash, + verificationVector[0] ); - IKeyStorage(contractManager.getContract("KeyStorage")).adding(schainHash, verificationVector[0]); emit BroadcastAndKeyShare( schainHash, nodeIndex, @@ -112,8 +115,11 @@ library SkaleDkgBroadcast { return (n * 2 + 1) / 3; } - function _getComplaintTimeLimit(IContractManager contractManager) private view returns (uint256 timeLimit) { - return IConstantsHolder(contractManager.getConstantsHolder()).complaintTimeLimit(); + function _getComplaintTimeLimit( + IContractManager contractManager + ) private view returns (uint256 timeLimit) { + return + IConstantsHolder(contractManager.getConstantsHolder()) + .complaintTimeLimit(); } - } diff --git a/contracts/dkg/SkaleDkgComplaint.sol b/contracts/dkg/SkaleDkgComplaint.sol index 3b628200d..c19fea010 100644 --- a/contracts/dkg/SkaleDkgComplaint.sol +++ b/contracts/dkg/SkaleDkgComplaint.sol @@ -23,9 +23,9 @@ pragma solidity 0.8.17; -import { ISkaleDKG } from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; -import { IConstantsHolder } from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; -import { IContractManager } from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; +import {ISkaleDKG} from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; +import {IConstantsHolder} from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; +import {IContractManager} from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; /** * @title SkaleDkgComplaint @@ -33,7 +33,6 @@ import { IContractManager } from "@skalenetwork/skale-manager-interfaces/IContra * Joint-Feldman protocol. */ library SkaleDkgComplaint { - /** * @dev Emitted when an incorrect complaint is sent. */ @@ -43,8 +42,10 @@ library SkaleDkgComplaint { * @dev Emitted when a complaint is sent. */ event ComplaintSent( - bytes32 indexed schainHash, uint256 indexed fromNodeIndex, uint256 indexed toNodeIndex); - + bytes32 indexed schainHash, + uint256 indexed fromNodeIndex, + uint256 indexed toNodeIndex + ); /** * @dev Creates a complaint from a node (accuser) to a given node. @@ -64,11 +65,12 @@ library SkaleDkgComplaint { mapping(bytes32 => ISkaleDKG.Channel) storage channels, mapping(bytes32 => ISkaleDKG.ComplaintData) storage complaints, mapping(bytes32 => uint256) storage startAlrightTimestamp - ) - external - { + ) external { ISkaleDKG skaleDKG = ISkaleDKG(contractManager.getContract("SkaleDKG")); - require(skaleDKG.isNodeBroadcasted(schainHash, fromNodeIndex), "Node has not broadcasted"); + require( + skaleDKG.isNodeBroadcasted(schainHash, fromNodeIndex), + "Node has not broadcasted" + ); if (skaleDKG.isNodeBroadcasted(schainHash, toNodeIndex)) { _handleComplaintWhenBroadcasted({ schainHash: schainHash, @@ -80,7 +82,12 @@ library SkaleDkgComplaint { }); } else { // not broadcasted in 30 min - _handleComplaintWhenNotBroadcasted(schainHash, toNodeIndex, contractManager, channels); + _handleComplaintWhenNotBroadcasted( + schainHash, + toNodeIndex, + contractManager, + channels + ); } skaleDKG.setBadNode(schainHash, toNodeIndex); } @@ -91,17 +98,25 @@ library SkaleDkgComplaint { uint256 toNodeIndex, IContractManager contractManager, mapping(bytes32 => ISkaleDKG.ComplaintData) storage complaints - ) - external - { + ) external { ISkaleDKG skaleDKG = ISkaleDKG(contractManager.getContract("SkaleDKG")); - require(skaleDKG.isNodeBroadcasted(schainHash, fromNodeIndex), "Node has not broadcasted"); - require(skaleDKG.isNodeBroadcasted(schainHash, toNodeIndex), "Accused node has not broadcasted"); - require(!skaleDKG.isAllDataReceived(schainHash, fromNodeIndex), "Node has already sent alright"); + require( + skaleDKG.isNodeBroadcasted(schainHash, fromNodeIndex), + "Node has not broadcasted" + ); + require( + skaleDKG.isNodeBroadcasted(schainHash, toNodeIndex), + "Accused node has not broadcasted" + ); + require( + !skaleDKG.isAllDataReceived(schainHash, fromNodeIndex), + "Node has already sent alright" + ); if (complaints[schainHash].nodeToComplaint == type(uint256).max) { complaints[schainHash].nodeToComplaint = toNodeIndex; complaints[schainHash].fromNodeToComplaint = fromNodeIndex; - complaints[schainHash].startComplaintBlockTimestamp = block.timestamp; + complaints[schainHash].startComplaintBlockTimestamp = block + .timestamp; emit ComplaintSent(schainHash, fromNodeIndex, toNodeIndex); } else { emit ComplaintError("First complaint has already been processed"); @@ -115,16 +130,16 @@ library SkaleDkgComplaint { IContractManager contractManager, mapping(bytes32 => ISkaleDKG.ComplaintData) storage complaints, mapping(bytes32 => uint256) storage startAlrightTimestamp - ) - private - { + ) private { ISkaleDKG skaleDKG = ISkaleDKG(contractManager.getContract("SkaleDKG")); // missing alright if (complaints[schainHash].nodeToComplaint == type(uint256).max) { if ( skaleDKG.isEveryoneBroadcasted(schainHash) && !skaleDKG.isAllDataReceived(schainHash, toNodeIndex) && - startAlrightTimestamp[schainHash] + _getComplaintTimeLimit(contractManager) <= block.timestamp + startAlrightTimestamp[schainHash] + + _getComplaintTimeLimit(contractManager) <= + block.timestamp ) { // missing alright skaleDKG.finalizeSlashing(schainHash, toNodeIndex); @@ -138,10 +153,15 @@ library SkaleDkgComplaint { return; } else if (complaints[schainHash].nodeToComplaint == toNodeIndex) { // 30 min after incorrect data complaint - if (complaints[schainHash].startComplaintBlockTimestamp + _getComplaintTimeLimit(contractManager) - <= block.timestamp + if ( + complaints[schainHash].startComplaintBlockTimestamp + + _getComplaintTimeLimit(contractManager) <= + block.timestamp ) { - skaleDKG.finalizeSlashing(schainHash, complaints[schainHash].nodeToComplaint); + skaleDKG.finalizeSlashing( + schainHash, + complaints[schainHash].nodeToComplaint + ); return; } emit ComplaintError("The same complaint rejected"); @@ -150,24 +170,31 @@ library SkaleDkgComplaint { emit ComplaintError("One complaint is already sent"); } - function _handleComplaintWhenNotBroadcasted( bytes32 schainHash, uint256 toNodeIndex, IContractManager contractManager, mapping(bytes32 => ISkaleDKG.Channel) storage channels - ) - private - { - if (channels[schainHash].startedBlockTimestamp + _getComplaintTimeLimit(contractManager) <= block.timestamp) { - ISkaleDKG(contractManager.getContract("SkaleDKG")).finalizeSlashing(schainHash, toNodeIndex); + ) private { + if ( + channels[schainHash].startedBlockTimestamp + + _getComplaintTimeLimit(contractManager) <= + block.timestamp + ) { + ISkaleDKG(contractManager.getContract("SkaleDKG")).finalizeSlashing( + schainHash, + toNodeIndex + ); return; } emit ComplaintError("Complaint sent too early"); } - function _getComplaintTimeLimit(IContractManager contractManager) private view returns (uint256 timeLimit) { - return IConstantsHolder(contractManager.getConstantsHolder()).complaintTimeLimit(); + function _getComplaintTimeLimit( + IContractManager contractManager + ) private view returns (uint256 timeLimit) { + return + IConstantsHolder(contractManager.getConstantsHolder()) + .complaintTimeLimit(); } - } diff --git a/contracts/dkg/SkaleDkgPreResponse.sol b/contracts/dkg/SkaleDkgPreResponse.sol index 282fe3d84..50054f938 100644 --- a/contracts/dkg/SkaleDkgPreResponse.sol +++ b/contracts/dkg/SkaleDkgPreResponse.sol @@ -23,12 +23,13 @@ pragma solidity 0.8.17; -import { ISkaleDKG } from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; -import { IContractManager } from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; +import {ISkaleDKG} from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; +import {IContractManager} from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; -import { G1Operations } from "../utils/fieldOperations/G1Operations.sol"; -import { G2Operations } from "../utils/fieldOperations/G2Operations.sol"; -import { Precompiled } from "../utils/Precompiled.sol"; +import {G1Operations} from "../utils/fieldOperations/G1Operations.sol"; +import {G2Operations} from "../utils/fieldOperations/G2Operations.sol"; +import {GroupIndexIsInvalid} from "../CommonErrors.sol"; +import {Precompiled} from "../utils/Precompiled.sol"; /** * @title SkaleDkgPreResponse @@ -47,9 +48,7 @@ library SkaleDkgPreResponse { IContractManager contractManager, mapping(bytes32 => ISkaleDKG.ComplaintData) storage complaints, mapping(bytes32 => mapping(uint256 => bytes32)) storage hashedData - ) - external - { + ) external { ISkaleDKG skaleDKG = ISkaleDKG(contractManager.getContract("SkaleDKG")); uint256 index = _preResponseCheck({ schainHash: schainHash, @@ -74,11 +73,11 @@ library SkaleDkgPreResponse { bytes32 schainHash, ISkaleDKG.G2Point[] memory verificationVectorMultiplication, mapping(bytes32 => ISkaleDKG.ComplaintData) storage complaints - ) - private - { + ) private { complaints[schainHash].keyShare = share; - complaints[schainHash].sumOfVerVec = _calculateSum(verificationVectorMultiplication); + complaints[schainHash].sumOfVerVec = _calculateSum( + verificationVectorMultiplication + ); complaints[schainHash].isResponse = true; } @@ -91,34 +90,51 @@ library SkaleDkgPreResponse { ISkaleDKG skaleDKG, mapping(bytes32 => ISkaleDKG.ComplaintData) storage complaints, mapping(bytes32 => mapping(uint256 => bytes32)) storage hashedData - ) - private - view - returns (uint256 index) - { - (uint256 indexOnSchain, ) = skaleDKG.checkAndReturnIndexInGroup(schainHash, fromNodeIndex, true); - require(complaints[schainHash].nodeToComplaint == fromNodeIndex, "Not this Node"); - require(!complaints[schainHash].isResponse, "Already submitted pre response data"); + ) private view returns (uint256 index) { + (uint256 indexOnSchain, bool valid) = skaleDKG + .checkAndReturnIndexInGroup(schainHash, fromNodeIndex, true); + if (!valid) { + revert GroupIndexIsInvalid(index); + } + require( + complaints[schainHash].nodeToComplaint == fromNodeIndex, + "Not this Node" + ); + require( + !complaints[schainHash].isResponse, + "Already submitted pre response data" + ); require( - hashedData[schainHash][indexOnSchain] == skaleDKG.hashData(secretKeyContribution, verificationVector), + hashedData[schainHash][indexOnSchain] == + skaleDKG.hashData(secretKeyContribution, verificationVector), "Broadcasted Data is not correct" ); require( - verificationVector.length == verificationVectorMultiplication.length, + verificationVector.length == + verificationVectorMultiplication.length, "Incorrect length of multiplied verification vector" ); - (index, ) = skaleDKG.checkAndReturnIndexInGroup(schainHash, complaints[schainHash].fromNodeToComplaint, true); + (index, valid) = skaleDKG.checkAndReturnIndexInGroup( + schainHash, + complaints[schainHash].fromNodeToComplaint, + true + ); + if (!valid) { + revert GroupIndexIsInvalid(index); + } require( - _checkCorrectVectorMultiplication(index, verificationVector, verificationVectorMultiplication), + _checkCorrectVectorMultiplication( + index, + verificationVector, + verificationVectorMultiplication + ), "Multiplied verification vector is incorrect" ); } - function _calculateSum(ISkaleDKG.G2Point[] memory verificationVectorMultiplication) - private - view - returns (ISkaleDKG.G2Point memory result) - { + function _calculateSum( + ISkaleDKG.G2Point[] memory verificationVectorMultiplication + ) private view returns (ISkaleDKG.G2Point memory result) { ISkaleDKG.G2Point memory value = G2Operations.getG2Zero(); for (uint256 i = 0; i < verificationVectorMultiplication.length; i++) { value = value.addG2(verificationVectorMultiplication[i]); @@ -130,16 +146,22 @@ library SkaleDkgPreResponse { uint256 indexOnSchain, ISkaleDKG.G2Point[] memory verificationVector, ISkaleDKG.G2Point[] memory verificationVectorMultiplication - ) - private - view - returns (bool correct) - { + ) private view returns (bool correct) { ISkaleDKG.Fp2Point memory value = G1Operations.getG1Generator(); ISkaleDKG.Fp2Point memory tmp = G1Operations.getG1Generator(); for (uint256 i = 0; i < verificationVector.length; i++) { - (tmp.a, tmp.b) = Precompiled.bn256ScalarMul(value.a, value.b, (indexOnSchain + 1) ** i); - if (!_checkPairing(tmp, verificationVector[i], verificationVectorMultiplication[i])) { + (tmp.a, tmp.b) = Precompiled.bn256ScalarMul( + value.a, + value.b, + (indexOnSchain + 1) ** i + ); + if ( + !_checkPairing( + tmp, + verificationVector[i], + verificationVectorMultiplication[i] + ) + ) { return false; } } @@ -150,28 +172,24 @@ library SkaleDkgPreResponse { ISkaleDKG.Fp2Point memory g1Mul, ISkaleDKG.G2Point memory verificationVector, ISkaleDKG.G2Point memory verificationVectorMultiplication - ) - private - view - returns (bool valid) - { + ) private view returns (bool valid) { require(G1Operations.checkRange(g1Mul), "g1Mul is not valid"); g1Mul.b = G1Operations.negate(g1Mul.b); ISkaleDKG.Fp2Point memory one = G1Operations.getG1Generator(); - return Precompiled.bn256Pairing({ - x1: one.a, - y1: one.b, - a1: verificationVectorMultiplication.x.b, - b1: verificationVectorMultiplication.x.a, - c1: verificationVectorMultiplication.y.b, - d1: verificationVectorMultiplication.y.a, - x2: g1Mul.a, - y2: g1Mul.b, - a2: verificationVector.x.b, - b2: verificationVector.x.a, - c2: verificationVector.y.b, - d2: verificationVector.y.a - }); + return + Precompiled.bn256Pairing({ + x1: one.a, + y1: one.b, + a1: verificationVectorMultiplication.x.b, + b1: verificationVectorMultiplication.x.a, + c1: verificationVectorMultiplication.y.b, + d1: verificationVectorMultiplication.y.a, + x2: g1Mul.a, + y2: g1Mul.b, + a2: verificationVector.x.b, + b2: verificationVector.x.a, + c2: verificationVector.y.b, + d2: verificationVector.y.a + }); } - } diff --git a/contracts/dkg/SkaleDkgResponse.sol b/contracts/dkg/SkaleDkgResponse.sol index 84872885e..4b7697d91 100644 --- a/contracts/dkg/SkaleDkgResponse.sol +++ b/contracts/dkg/SkaleDkgResponse.sol @@ -23,17 +23,17 @@ pragma solidity 0.8.17; -import { ISkaleDKG } from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; -import { ISchainsInternal } from "@skalenetwork/skale-manager-interfaces/ISchainsInternal.sol"; -import { IDecryption } from "@skalenetwork/skale-manager-interfaces/IDecryption.sol"; -import { INodes } from "@skalenetwork/skale-manager-interfaces/INodes.sol"; -import { IECDH } from "@skalenetwork/skale-manager-interfaces/thirdparty/IECDH.sol"; -import { IContractManager } from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; -import { IConstantsHolder } from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; - -import { G1Operations } from "../utils/fieldOperations/G1Operations.sol"; -import { G2Operations } from "../utils/fieldOperations/G2Operations.sol"; -import { Precompiled } from "../utils/Precompiled.sol"; +import {ISkaleDKG} from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; +import {ISchainsInternal} from "@skalenetwork/skale-manager-interfaces/ISchainsInternal.sol"; +import {IDecryption} from "@skalenetwork/skale-manager-interfaces/IDecryption.sol"; +import {INodes} from "@skalenetwork/skale-manager-interfaces/INodes.sol"; +import {IECDH} from "@skalenetwork/skale-manager-interfaces/thirdparty/IECDH.sol"; +import {IContractManager} from "@skalenetwork/skale-manager-interfaces/IContractManager.sol"; +import {IConstantsHolder} from "@skalenetwork/skale-manager-interfaces/IConstantsHolder.sol"; + +import {G1Operations} from "../utils/fieldOperations/G1Operations.sol"; +import {G2Operations} from "../utils/fieldOperations/G2Operations.sol"; +import {Precompiled} from "../utils/Precompiled.sol"; /** * @title SkaleDkgResponse @@ -51,19 +51,25 @@ library SkaleDkgResponse { IContractManager contractManager, mapping(bytes32 => ISkaleDKG.Channel) storage channels, mapping(bytes32 => ISkaleDKG.ComplaintData) storage complaints - ) - external - { - uint256 index = ISchainsInternal(contractManager.getContract("SchainsInternal")) - .getNodeIndexInGroup(schainHash, fromNodeIndex); + ) external { + uint256 index = ISchainsInternal( + contractManager.getContract("SchainsInternal") + ).getNodeIndexInGroup(schainHash, fromNodeIndex); require(index < channels[schainHash].n, "Node is not in this group"); - require(complaints[schainHash].nodeToComplaint == fromNodeIndex, "Not this Node"); require( - complaints[schainHash].startComplaintBlockTimestamp - + _getComplaintTimeLimit(contractManager) > block.timestamp, + complaints[schainHash].nodeToComplaint == fromNodeIndex, + "Not this Node" + ); + require( + complaints[schainHash].startComplaintBlockTimestamp + + _getComplaintTimeLimit(contractManager) > + block.timestamp, "Incorrect time for response" ); - require(complaints[schainHash].isResponse, "Have not submitted pre-response data"); + require( + complaints[schainHash].isResponse, + "Have not submitted pre-response data" + ); uint256 badNode = _verifyDataAndSlash({ schainHash: schainHash, secretNumber: secretNumber, @@ -71,7 +77,10 @@ library SkaleDkgResponse { contractManager: contractManager, complaints: complaints }); - ISkaleDKG(contractManager.getContract("SkaleDKG")).setBadNode(schainHash, badNode); + ISkaleDKG(contractManager.getContract("SkaleDKG")).setBadNode( + schainHash, + badNode + ); } function _verifyDataAndSlash( @@ -80,50 +89,51 @@ library SkaleDkgResponse { ISkaleDKG.G2Point memory multipliedShare, IContractManager contractManager, mapping(bytes32 => ISkaleDKG.ComplaintData) storage complaints - ) - private - returns (uint256 badNode) - { - bytes32[2] memory publicKey = INodes(contractManager.getContract("Nodes")).getNodePublicKey( - complaints[schainHash].fromNodeToComplaint - ); + ) private returns (uint256 badNode) { + bytes32[2] memory publicKey = INodes( + contractManager.getContract("Nodes") + ).getNodePublicKey(complaints[schainHash].fromNodeToComplaint); uint256 pkX = uint256(publicKey[0]); - (pkX, ) = IECDH(contractManager.getContract("ECDH")).deriveKey(secretNumber, pkX, uint256(publicKey[1])); + // Value of pkY is not needed for proper DKG work. + // Encoding is only done by using half of the keys. + // slither-disable-next-line unused-return + (pkX, ) = IECDH(contractManager.getContract("ECDH")).deriveKey( + secretNumber, + pkX, + uint256(publicKey[1]) + ); bytes32 key = bytes32(pkX); // Decrypt secret key contribution - uint256 secret = IDecryption(contractManager.getContract("Decryption")).decrypt( - complaints[schainHash].keyShare, - sha256(abi.encodePacked(key)) - ); + uint256 secret = IDecryption(contractManager.getContract("Decryption")) + .decrypt( + complaints[schainHash].keyShare, + sha256(abi.encodePacked(key)) + ); badNode = ( _checkCorrectMultipliedShare(multipliedShare, secret) && - multipliedShare.isEqual(complaints[schainHash].sumOfVerVec) ? - complaints[schainHash].fromNodeToComplaint : - complaints[schainHash].nodeToComplaint + multipliedShare.isEqual(complaints[schainHash].sumOfVerVec) + ? complaints[schainHash].fromNodeToComplaint + : complaints[schainHash].nodeToComplaint + ); + ISkaleDKG(contractManager.getContract("SkaleDKG")).finalizeSlashing( + schainHash, + badNode ); - ISkaleDKG(contractManager.getContract("SkaleDKG")).finalizeSlashing(schainHash, badNode); } function _checkCorrectMultipliedShare( ISkaleDKG.G2Point memory multipliedShare, uint256 secret - ) - private - view - returns (bool correct) - { + ) private view returns (bool correct) { if (!multipliedShare.isG2()) { return false; } ISkaleDKG.G2Point memory tmp = multipliedShare; ISkaleDKG.Fp2Point memory g1 = G1Operations.getG1Generator(); - ISkaleDKG.Fp2Point memory share = ISkaleDKG.Fp2Point({ - a: 0, - b: 0 - }); + ISkaleDKG.Fp2Point memory share = ISkaleDKG.Fp2Point({a: 0, b: 0}); (share.a, share.b) = Precompiled.bn256ScalarMul(g1.a, g1.b, secret); require(G1Operations.checkRange(share), "share is not valid"); share.b = G1Operations.negate(share.b); @@ -132,24 +142,28 @@ library SkaleDkgResponse { ISkaleDKG.G2Point memory g2 = G2Operations.getG2Generator(); - return Precompiled.bn256Pairing({ - x1: share.a, - y1: share.b, - a1: g2.x.b, - b1: g2.x.a, - c1: g2.y.b, - d1: g2.y.a, - x2: g1.a, - y2: g1.b, - a2: tmp.x.b, - b2: tmp.x.a, - c2: tmp.y.b, - d2: tmp.y.a - }); + return + Precompiled.bn256Pairing({ + x1: share.a, + y1: share.b, + a1: g2.x.b, + b1: g2.x.a, + c1: g2.y.b, + d1: g2.y.a, + x2: g1.a, + y2: g1.b, + a2: tmp.x.b, + b2: tmp.x.a, + c2: tmp.y.b, + d2: tmp.y.a + }); } - function _getComplaintTimeLimit(IContractManager contractManager) private view returns (uint256 timeLimit) { - return IConstantsHolder(contractManager.getConstantsHolder()).complaintTimeLimit(); + function _getComplaintTimeLimit( + IContractManager contractManager + ) private view returns (uint256 timeLimit) { + return + IConstantsHolder(contractManager.getConstantsHolder()) + .complaintTimeLimit(); } - } diff --git a/contracts/test/ImaMock.sol b/contracts/test/ImaMock.sol new file mode 100644 index 000000000..d52baff85 --- /dev/null +++ b/contracts/test/ImaMock.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/* + LockerMock.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 . +*/ + +pragma solidity 0.8.26; + +import { IMessageListener } from "@skalenetwork/ima-interfaces/IMessageListener.sol"; + +contract ImaMock is IMessageListener { + event MessageProcessed( + address sender, + address destinationContract, + bytes data + ); + + event MessageSent( + bytes32 targetChainHash, + address targetContract, + bytes data + ); + + function postIncomingMessages( + string calldata /* fromSchainName */, + uint256 /* startingCounter */, + Message[] calldata messages, + Signature calldata /* sign */ + ) external override { + for (uint256 i = 0; i < messages.length; ++i) { + emit MessageProcessed( + messages[i].sender, + messages[i].destinationContract, + messages[i].data + ); + } + } + + function postOutgoingMessage( + bytes32 targetChainHash, + address targetContract, + bytes memory data + ) external override { + emit MessageSent(targetChainHash, targetContract, data); + } +} diff --git a/contracts/test/LockerMock.sol b/contracts/test/LockerMock.sol index 813f7962f..c3a36b349 100644 --- a/contracts/test/LockerMock.sol +++ b/contracts/test/LockerMock.sol @@ -28,7 +28,14 @@ contract LockerMock is ILocker { return 13; } - function getAndUpdateForbiddenForDelegationAmount(address) external pure override returns (uint256 amount) { + function getAndUpdateForbiddenForDelegationAmount( + address + ) + external + pure + override + returns (uint256 amount) + { return 13; } } diff --git a/contracts/test/MathUtilsTester.sol b/contracts/test/MathUtilsTester.sol index 315921395..4d393988e 100644 --- a/contracts/test/MathUtilsTester.sol +++ b/contracts/test/MathUtilsTester.sol @@ -32,7 +32,15 @@ contract MathUtilsTester is IMathUtilsTester { return a.boundedSub(b); } - function boundedSubWithoutEvent(uint256 a, uint256 b) external pure override returns (uint256 result) { + function boundedSubWithoutEvent( + uint256 a, + uint256 b + ) + external + pure + override + returns (uint256 result) + { return a.boundedSubWithoutEvent(b); } diff --git a/contracts/test/NodesMock.sol b/contracts/test/NodesMock.sol index b06153938..34a716c84 100644 --- a/contracts/test/NodesMock.sol +++ b/contracts/test/NodesMock.sol @@ -53,7 +53,14 @@ contract NodesMock is Permissions, INodesMock { function changeNodeLastRewardDate(uint256 nodeId) external override { lastRewardDate[nodeId] = block.timestamp; } - function getNodeLastRewardDate(uint256 nodeIndex) external view override returns (uint256 timestamp) { + function getNodeLastRewardDate( + uint256 nodeIndex + ) + external + view + override + returns (uint256 timestamp) + { require(nodeIndex < nodesCount, "Node does not exist"); return lastRewardDate[nodeIndex]; } diff --git a/contracts/test/PartialDifferencesTester.sol b/contracts/test/PartialDifferencesTester.sol index e203f1628..f5f16395d 100644 --- a/contracts/test/PartialDifferencesTester.sol +++ b/contracts/test/PartialDifferencesTester.sol @@ -46,7 +46,14 @@ contract PartialDifferencesTester is IPartialDifferencesTester { _sequences[sequence].subtractFromSequence(diff, month); } - function getAndUpdateSequenceItem(uint256 sequence, uint256 month) external override returns (uint256 item) { + function getAndUpdateSequenceItem( + uint256 sequence, + uint256 month + ) + external + override + returns (uint256 item) + { require(sequence < _sequences.length, "Sequence does not exist"); return _sequences[sequence].getAndUpdateValueInSequence(month); } diff --git a/contracts/test/ReentrancyTester.sol b/contracts/test/ReentrancyTester.sol index da091fa1b..418108413 100644 --- a/contracts/test/ReentrancyTester.sol +++ b/contracts/test/ReentrancyTester.sol @@ -34,15 +34,22 @@ import { IReentrancyTester } from "./interfaces/IReentrancyTester.sol"; contract ReentrancyTester is Permissions, IERC777Recipient, IERC777Sender, IReentrancyTester { - IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); + IERC1820Registry private _erc1820 = + IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); bool private _reentrancyCheck = false; bool private _burningAttack = false; uint256 private _amount = 0; constructor (address contractManagerAddress) { Permissions.initialize(contractManagerAddress); - _erc1820.setInterfaceImplementer(address(this), keccak256("ERC777TokensRecipient"), address(this)); - _erc1820.setInterfaceImplementer(address(this), keccak256("ERC777TokensSender"), address(this)); + _erc1820.setInterfaceImplementer( + address(this), + keccak256("ERC777TokensRecipient"), address(this) + ); + _erc1820.setInterfaceImplementer( + address(this), + keccak256("ERC777TokensSender"), address(this) + ); } function tokensReceived( diff --git a/contracts/test/SafeMock.sol b/contracts/test/SafeMock.sol index 1ca75adfb..5c8f5cdc7 100644 --- a/contracts/test/SafeMock.sol +++ b/contracts/test/SafeMock.sol @@ -21,7 +21,9 @@ pragma solidity 0.8.17; -import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { + OwnableUpgradeable +} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { ISafeMock } from "./interfaces/ISafeMock.sol"; @@ -30,8 +32,9 @@ contract SafeMock is OwnableUpgradeable, ISafeMock { bool public constant IS_SAFE_MOCK = true; bytes32 public constant SAFE_TX_TYPE_HASH = keccak256( - "SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice," - "address gasToken,address refundReceiver,uint256 nonce)" + "SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas," + "uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver," + "uint256 nonce)" ); bytes32 public constant DOMAIN_SEPARATOR_TYPE_HASH = keccak256( "EIP712Domain(uint256 chainId,address verifyingContract)" @@ -42,7 +45,14 @@ contract SafeMock is OwnableUpgradeable, ISafeMock { multiSend(""); // this is needed to remove slither warning } - function transferProxyAdminOwnership(OwnableUpgradeable proxyAdmin, address newOwner) external override onlyOwner { + function transferProxyAdminOwnership( + OwnableUpgradeable proxyAdmin, + address newOwner + ) + external + override + onlyOwner + { proxyAdmin.transferOwnership(newOwner); } @@ -52,7 +62,7 @@ contract SafeMock is OwnableUpgradeable, ISafeMock { /// @dev Sends multiple transactions and reverts all if one fails. /// @param transactions Encoded transactions. Each transaction is encoded as a packed bytes of - /// operation as a uint8 with 0 for a call or 1 for a delegatecall (=> 1 byte), + /// operation as a uint8 with 0 for a call or 1 for a delegatecall, /// to as a address (=> 20 bytes), /// value as a uint256 (=> 32 bytes), /// data length as a uint256 (=> 32 bytes), @@ -79,7 +89,8 @@ contract SafeMock is OwnableUpgradeable, ISafeMock { let to := shr(0x60, mload(add(transactions, add(i, 0x01)))) // We offset the load address by 21 byte (operation byte + 20 address bytes) let value := mload(add(transactions, add(i, 0x15))) - // We offset the load address by 53 byte (operation byte + 20 address bytes + 32 value bytes) + // We offset the load address by 53 byte + // (operation byte + 20 address bytes + 32 value bytes) let dataLength := mload(add(transactions, add(i, 0x35))) // We offset the load address by 85 byte // (operation byte + 20 address bytes + 32 value bytes + 32 data length bytes) diff --git a/contracts/test/SchainsInternalMock.sol b/contracts/test/SchainsInternalMock.sol index f6bd4292b..6d1668177 100644 --- a/contracts/test/SchainsInternalMock.sol +++ b/contracts/test/SchainsInternalMock.sol @@ -45,11 +45,27 @@ contract SchainsInternalMock is SchainsInternal, ISchainsInternalMock { delete schainToException[schainHash]; } - function _addAddressToSchain(bytes32, address) internal override pure returns (bool successful) { + function _addAddressToSchain( + bytes32, + address + ) + internal + override + pure + returns (bool successful) + { return true; } - function _removeAddressFromSchain(bytes32, address) internal override pure returns (bool successful) { + function _removeAddressFromSchain( + bytes32, + address + ) + internal + override + pure + returns (bool successful) + { return true; } } diff --git a/contracts/test/SegmentTreeTester.sol b/contracts/test/SegmentTreeTester.sol index b0088b3c6..e44e9af50 100644 --- a/contracts/test/SegmentTreeTester.sol +++ b/contracts/test/SegmentTreeTester.sol @@ -20,7 +20,7 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; +pragma solidity 0.8.26; import { IRandom, Random, SegmentTree } from "../utils/SegmentTree.sol"; import { ISegmentTreeTester } from "./interfaces/ISegmentTreeTester.sol"; @@ -58,7 +58,14 @@ contract SegmentTreeTester is ISegmentTreeTester { _tree.removeFromPlace(place, elem); } - function moveFromPlaceToPlace(uint256 fromPlace, uint256 toPlace, uint256 elem) external override { + function moveFromPlaceToPlace( + uint256 fromPlace, + uint256 toPlace, + uint256 elem + ) + external + override + { _tree.moveFromPlaceToPlace(fromPlace, toPlace, elem); } diff --git a/contracts/test/SkaleManagerMock.sol b/contracts/test/SkaleManagerMock.sol index 8e895dbfe..e2ce88a0f 100644 --- a/contracts/test/SkaleManagerMock.sol +++ b/contracts/test/SkaleManagerMock.sol @@ -32,21 +32,33 @@ import { ISkaleManagerMock } from "./interfaces/ISkaleManagerMock.sol"; contract SkaleManagerMock is Permissions, IERC777Recipient, ISkaleManagerMock { - IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); + IERC1820Registry private _erc1820 = + IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); bytes32 constant public ADMIN_ROLE = keccak256("ADMIN_ROLE"); constructor (address contractManagerAddress) { Permissions.initialize(contractManagerAddress); - _erc1820.setInterfaceImplementer(address(this), keccak256("ERC777TokensRecipient"), address(this)); + _erc1820.setInterfaceImplementer( + address(this), + keccak256("ERC777TokensRecipient"), + address(this) + ); } function payBounty(uint256 validatorId, uint256 amount) external override { IERC777 skaleToken = IERC777(contractManager.getContract("SkaleToken")); - require(IMintableToken(address(skaleToken)).mint(address(this), amount, "", ""), "Token was not minted"); require( - IMintableToken(address(skaleToken)) - .mint(contractManager.getContract("Distributor"), amount, abi.encode(validatorId), ""), + IMintableToken(address(skaleToken)).mint(address(this), amount, "", ""), + "Token was not minted" + ); + require( + IMintableToken(address(skaleToken)).mint( + contractManager.getContract("Distributor"), + amount, + abi.encode(validatorId), + "" + ), "Token was not minted" ); } diff --git a/contracts/test/TimeHelpersWithDebug.sol b/contracts/test/TimeHelpersWithDebug.sol index fb27b805c..cb2e5d80f 100644 --- a/contracts/test/TimeHelpersWithDebug.sol +++ b/contracts/test/TimeHelpersWithDebug.sol @@ -21,7 +21,9 @@ pragma solidity 0.8.17; -import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { + OwnableUpgradeable +} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { TimeHelpers } from "../delegation/TimeHelpers.sol"; import { ITimeHelpersWithDebug } from "./interfaces/ITimeHelpersWithDebug.sol"; @@ -90,9 +92,16 @@ contract TimeHelpersWithDebug is TimeHelpers, OwnableUpgradeable, ITimeHelpersWi } } - function _findTimeBeforeTimeShift(uint256 shiftedTimestamp) private view returns (uint256 timestamp) { + function _findTimeBeforeTimeShift( + uint256 shiftedTimestamp + ) + private + view + returns (uint256 timestamp) + { uint256 lastTimeShiftIndex = _timeShift.length - 1; - if (_timeShift[lastTimeShiftIndex].pointInTime + _timeShift[lastTimeShiftIndex].shift < shiftedTimestamp) { + if (_timeShift[lastTimeShiftIndex].pointInTime + _timeShift[lastTimeShiftIndex].shift + < shiftedTimestamp) { return shiftedTimestamp - _timeShift[lastTimeShiftIndex].shift; } else { if (shiftedTimestamp <= _timeShift[0].pointInTime + _timeShift[0].shift) { @@ -106,7 +115,8 @@ contract TimeHelpersWithDebug is TimeHelpers, OwnableUpgradeable, ITimeHelpersWi uint256 right = lastTimeShiftIndex; while (left + 1 < right) { uint256 middle = (left + right) / 2; - if (_timeShift[middle].pointInTime + _timeShift[middle].shift < shiftedTimestamp) { + if (_timeShift[middle].pointInTime + _timeShift[middle].shift + < shiftedTimestamp) { left = middle; } else { right = middle; diff --git a/contracts/test/interfaces/IPartialDifferencesTester.sol b/contracts/test/interfaces/IPartialDifferencesTester.sol index 4860a3c85..f38964db2 100644 --- a/contracts/test/interfaces/IPartialDifferencesTester.sol +++ b/contracts/test/interfaces/IPartialDifferencesTester.sol @@ -26,7 +26,10 @@ interface IPartialDifferencesTester { function createSequence() external; function addToSequence(uint256 sequence, uint256 diff, uint256 month) external; function subtractFromSequence(uint256 sequence, uint256 diff, uint256 month) external; - function getAndUpdateSequenceItem(uint256 sequence, uint256 month) external returns (uint256 item); + function getAndUpdateSequenceItem( + uint256 sequence, + uint256 month + ) external returns (uint256 item); function reduceSequence( uint256 sequence, uint256 a, diff --git a/contracts/test/interfaces/ISafeMock.sol b/contracts/test/interfaces/ISafeMock.sol index d32b97df4..d83b1e656 100644 --- a/contracts/test/interfaces/ISafeMock.sol +++ b/contracts/test/interfaces/ISafeMock.sol @@ -21,7 +21,9 @@ pragma solidity 0.8.17; -import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { + OwnableUpgradeable +} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; interface ISafeMock { diff --git a/contracts/test/interfaces/ISegmentTreeTester.sol b/contracts/test/interfaces/ISegmentTreeTester.sol index 6aff638cc..097fb6cc3 100644 --- a/contracts/test/interfaces/ISegmentTreeTester.sol +++ b/contracts/test/interfaces/ISegmentTreeTester.sol @@ -19,7 +19,7 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; +pragma solidity 0.8.26; interface ISegmentTreeTester { diff --git a/contracts/thirdparty/openzeppelin/ERC777.sol b/contracts/thirdparty/openzeppelin/ERC777.sol index e892f6917..49449aeb5 100644 --- a/contracts/thirdparty/openzeppelin/ERC777.sol +++ b/contracts/thirdparty/openzeppelin/ERC777.sol @@ -13,10 +13,6 @@ import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol"; -/* Added by SKALE */ -import "../../Permissions.sol"; -/* End of added by SKALE */ - /** * @dev Implementation of the {IERC777} interface. * diff --git a/contracts/utils/FractionUtils.sol b/contracts/utils/FractionUtils.sol index 39a5bf417..cd0005f58 100644 --- a/contracts/utils/FractionUtils.sol +++ b/contracts/utils/FractionUtils.sol @@ -29,7 +29,14 @@ library FractionUtils { uint256 denominator; } - function createFraction(uint256 numerator, uint256 denominator) internal pure returns (Fraction memory fraction) { + 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); @@ -46,8 +53,16 @@ library FractionUtils { 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) { + // 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); } diff --git a/contracts/utils/Precompiled.sol b/contracts/utils/Precompiled.sol index 5720baab7..f077ede65 100644 --- a/contracts/utils/Precompiled.sol +++ b/contracts/utils/Precompiled.sol @@ -19,12 +19,20 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; +pragma solidity ^0.8.17; library Precompiled { - function bigModExp(uint256 base, uint256 power, uint256 modulus) internal view returns (uint256 value) { + function bigModExp( + uint256 base, + uint256 power, + uint256 modulus + ) + internal + view + returns (uint256 value) + { uint256[6] memory inputToBigModExp; inputToBigModExp[0] = 32; inputToBigModExp[1] = 32; @@ -42,7 +50,15 @@ library Precompiled { return out[0]; } - function bn256ScalarMul(uint256 x, uint256 y, uint256 k) internal view returns (uint256 xValue, uint256 yValue) { + function bn256ScalarMul( + uint256 x, + uint256 y, + uint256 k + ) + internal + view + returns (uint256 xValue, uint256 yValue) + { uint256[3] memory inputToMul; uint256[2] memory output; inputToMul[0] = x; diff --git a/contracts/utils/Random.sol b/contracts/utils/Random.sol index 290b9f511..d4f14a5dd 100644 --- a/contracts/utils/Random.sol +++ b/contracts/utils/Random.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-only /* - SegmentTree.sol - SKALE Manager + Random.sol - SKALE Manager Copyright (C) 2018-Present SKALE Labs @author Artem Payvin @author Dmytro Stebaiev @@ -20,7 +20,7 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; +pragma solidity ^0.8.17; import { IRandom } from "@skalenetwork/skale-manager-interfaces/utils/IRandom.sol"; @@ -37,7 +37,13 @@ library Random { return IRandom.RandomGenerator({seed: seed}); } - function createFromEntropy(bytes memory entropy) internal pure returns (IRandom.RandomGenerator memory generator) { + function createFromEntropy( + bytes memory entropy + ) + internal + pure + returns (IRandom.RandomGenerator memory generator) + { return create(uint(keccak256(entropy))); } @@ -52,7 +58,14 @@ library Random { /** * @dev Generates random value in range [0, max) */ - function random(IRandom.RandomGenerator memory self, uint256 max) internal pure returns (uint256 value) { + function random( + IRandom.RandomGenerator memory self, + uint256 max + ) + internal + pure + returns (uint256 value) + { assert(max > 0); uint256 maxRand = type(uint256).max - type(uint256).max % max; if (type(uint).max - maxRand == max - 1) { diff --git a/contracts/utils/SegmentTree.sol b/contracts/utils/SegmentTree.sol index cdbeab9c4..337d080de 100644 --- a/contracts/utils/SegmentTree.sol +++ b/contracts/utils/SegmentTree.sol @@ -20,7 +20,7 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; +pragma solidity 0.8.26; import { IRandom, Random } from "./Random.sol"; @@ -251,7 +251,14 @@ library SegmentTree { * * - `place` must be in range [1, size] */ - function sumFromPlaceToLast(Tree storage self, uint256 place) public view returns (uint256 sum) { + function sumFromPlaceToLast( + Tree storage self, + uint256 place + ) + public + view + returns (uint256 sum) + { require(_correctPlace(self, place), "Incorrect place"); if (place == 1) { return self.tree[0]; diff --git a/contracts/utils/StringUtils.sol b/contracts/utils/StringUtils.sol index a6af0d20d..6caebd68e 100644 --- a/contracts/utils/StringUtils.sol +++ b/contracts/utils/StringUtils.sol @@ -24,7 +24,14 @@ pragma solidity 0.8.17; library StringUtils { - function strConcat(string memory a, string memory b) internal pure returns (string memory result) { + function strConcat( + string memory a, + string memory b + ) + internal + pure + returns (string memory result) + { bytes memory _ba = bytes(a); bytes memory _bb = bytes(b); diff --git a/contracts/utils/fieldOperations/Fp2Operations.sol b/contracts/utils/fieldOperations/Fp2Operations.sol index b8a4ea405..5215f6c26 100644 --- a/contracts/utils/fieldOperations/Fp2Operations.sol +++ b/contracts/utils/fieldOperations/Fp2Operations.sol @@ -22,7 +22,7 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; +pragma solidity ^0.8.17; import { ISkaleDKG } from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; @@ -31,9 +31,16 @@ import { Precompiled } from "../Precompiled.sol"; library Fp2Operations { - uint256 constant public P = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + uint256 constant public P = + 21888242871839275222246405745257275088696311157297823662689037894645226208583; - function inverseFp2(ISkaleDKG.Fp2Point memory value) internal view returns (ISkaleDKG.Fp2Point memory result) { + function inverseFp2( + ISkaleDKG.Fp2Point memory value + ) + internal + view + returns (ISkaleDKG.Fp2Point memory result) + { uint256 p = P; uint256 t0 = mulmod(value.a, value.a, p); uint256 t1 = mulmod(value.b, value.b, p); @@ -53,7 +60,10 @@ library Fp2Operations { pure returns (ISkaleDKG.Fp2Point memory result) { - return ISkaleDKG.Fp2Point({ a: addmod(value1.a, value2.a, P), b: addmod(value1.b, value2.b, P) }); + return ISkaleDKG.Fp2Point({ + a: addmod(value1.a, value2.a, P), + b: addmod(value1.b, value2.b, P) + }); } function scalarMulFp2(ISkaleDKG.Fp2Point memory value, uint256 scalar) @@ -64,7 +74,12 @@ library Fp2Operations { return ISkaleDKG.Fp2Point({ a: mulmod(scalar, value.a, P), b: mulmod(scalar, value.b, P) }); } - function minusFp2(ISkaleDKG.Fp2Point memory diminished, ISkaleDKG.Fp2Point memory subtracted) internal pure + function minusFp2( + ISkaleDKG.Fp2Point memory diminished, + ISkaleDKG.Fp2Point memory subtracted + ) + internal + pure returns (ISkaleDKG.Fp2Point memory difference) { uint256 p = P; @@ -105,10 +120,20 @@ library Fp2Operations { p); } - function squaredFp2(ISkaleDKG.Fp2Point memory value) internal pure returns (ISkaleDKG.Fp2Point memory result) { + function squaredFp2( + ISkaleDKG.Fp2Point memory value + ) + internal + pure + returns (ISkaleDKG.Fp2Point memory result) + { uint256 p = P; uint256 ab = mulmod(value.a, value.b, p); - uint256 multiplication = mulmod(addmod(value.a, value.b, p), addmod(value.a, mulmod(p - 1, value.b, p), p), p); + uint256 multiplication = mulmod( + addmod(value.a, value.b, p), + addmod(value.a, mulmod(p - 1, value.b, p), p), + p + ); return ISkaleDKG.Fp2Point({ a: multiplication, b: addmod(ab, ab, p) }); } diff --git a/contracts/utils/fieldOperations/G2Operations.sol b/contracts/utils/fieldOperations/G2Operations.sol index 5f4cc422e..e201713e8 100644 --- a/contracts/utils/fieldOperations/G2Operations.sol +++ b/contracts/utils/fieldOperations/G2Operations.sol @@ -22,7 +22,7 @@ along with SKALE Manager. If not, see . */ -pragma solidity 0.8.17; +pragma solidity ^0.8.17; import { ISkaleDKG } from "@skalenetwork/skale-manager-interfaces/ISkaleDKG.sol"; @@ -75,7 +75,13 @@ library G2Operations { return sum; } - ISkaleDKG.Fp2Point memory s = value2.y.minusFp2(value1.y).mulFp2(value2.x.minusFp2(value1.x).inverseFp2()); + ISkaleDKG.Fp2Point memory s = value2.y + .minusFp2(value1.y) + .mulFp2( + value2.x + .minusFp2(value1.x) + .inverseFp2() + ); sum.x = s.squaredFp2().minusFp2(value1.x.addFp2(value2.x)); sum.y = value1.y.addFp2(s.mulFp2(sum.x.minusFp2(value1.x))); uint256 p = Fp2Operations.P; @@ -122,7 +128,14 @@ library G2Operations { }); } - function isG2Point(ISkaleDKG.Fp2Point memory x, ISkaleDKG.Fp2Point memory y) internal pure returns (bool result) { + function isG2Point( + ISkaleDKG.Fp2Point memory x, + ISkaleDKG.Fp2Point memory y + ) + internal + pure + returns (bool result) + { if (isG2ZeroPoint(x, y)) { return true; } diff --git a/hardhat.config.ts b/hardhat.config.ts index cc5f5d9c5..d676a76a6 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -82,6 +82,15 @@ const config: HardhatUserConfig = { runs: 100 } } + }, + { + version: '0.8.26', + settings: { + optimizer: { + enabled: true, + runs: 300 + } + } } ] }, diff --git a/migrations/deploy.ts b/migrations/deploy.ts index 9936fd0d3..60705c1bd 100644 --- a/migrations/deploy.ts +++ b/migrations/deploy.ts @@ -61,10 +61,10 @@ export const contracts = [ "SkaleDKG", "SkaleVerifier", "SkaleManager", - "Pricing", "BountyV2", "Wallets", - "SyncManager" + "SyncManager", + "PaymasterController" ] async function main() { diff --git a/migrations/upgrade.ts b/migrations/upgrade.ts index 3975137f2..b4d0d4923 100644 --- a/migrations/upgrade.ts +++ b/migrations/upgrade.ts @@ -1,9 +1,9 @@ import chalk from "chalk"; import {contracts} from "./deploy"; -import {ethers} from "hardhat"; +import {ethers, upgrades} from "hardhat"; import {Upgrader, AutoSubmitter} from "@skalenetwork/upgrade-tools"; import {skaleContracts, Instance} from "@skalenetwork/skale-contracts-ethers-v6"; -import {SkaleManager} from "../typechain-types"; +import {ContractManager, PaymasterController, SkaleManager} from "../typechain-types"; import {Manifest, getImplementationAddress} from "@openzeppelin/upgrades-core"; import {Transaction} from "ethers"; @@ -59,7 +59,57 @@ class SkaleManagerUpgrader extends Upgrader { })); } - // deployNewContracts = () => { }; + deployNewContracts = async () => { + const [deployer] = await ethers.getSigners(); + + const contractManager = await this.instance.getContract("ContractManager") as ContractManager; + + const paymasterControllerFactory = await ethers.getContractFactory("PaymasterController"); + console.log("Deploy PaymasterController"); + const paymasterController = await upgrades.deployProxy( + paymasterControllerFactory, + [await ethers.resolveAddress(contractManager)] + ) as unknown as PaymasterController; + await paymasterController.deploymentTransaction()?.wait(); + + const ima = process.env.IMA ?? "0x8629703a9903515818C2FeB45a6f6fA5df8Da404"; + const marionette = process.env.MARIONETTE ?? "0xef777804e94eac176bbdbb3b3c9da06de87227ba"; + const paymaster = process.env.PAYMASTER ?? "0x0d66cA00CbAD4219734D7FDF921dD7Caadc1F78D"; + const paymasterChainHash = process.env.PAYMASTER_CHAIN_HASH ?? ethers.solidityPackedKeccak256(["string"], ["elated-tan-skat"]); // Europa + + console.log(`Set IMA address to ${ima}`); + await (await paymasterController.setImaAddress(ima)).wait(); + + console.log(`Set Marionette address to ${marionette}`); + await (await paymasterController.setMarionetteAddress(marionette)).wait(); + + console.log(`Set Paymaster address to ${paymaster}`); + await (await paymasterController.setPaymasterAddress(paymaster)).wait(); + + console.log(`Set Paymaster schain hash to ${paymasterChainHash}`); + await (await paymasterController.setPaymasterChainHash(paymasterChainHash)).wait(); + + console.log("Revoke PAYMASTER_SETTER_ROLE"); + await (await paymasterController.revokeRole( + await paymasterController.PAYMASTER_SETTER_ROLE(), + deployer + )).wait(); + + const owner = await contractManager.owner(); + if (!await paymasterController.hasRole(await paymasterController.DEFAULT_ADMIN_ROLE(), owner)) { + console.log(`Grant ownership to ${owner}`); + await (await paymasterController.grantRole( + await paymasterController.DEFAULT_ADMIN_ROLE(), + owner + )).wait(); + + console.log(`Revoke ownership from ${ethers.resolveAddress(deployer)}`); + await (await paymasterController.revokeRole( + await paymasterController.DEFAULT_ADMIN_ROLE(), + deployer + )).wait(); + } + }; // initialize = async () => { }; } @@ -97,10 +147,21 @@ async function prepareContractsList(instance: Instance) { async function main() { const skaleManager = await getSkaleManagerInstance(); + let contractsToUpgrade = [ + "Nodes", + "Schains", + "ValidatorService" + ]; + if (process.env.UPGRADE_ALL) { + contractsToUpgrade = await prepareContractsList(skaleManager); + } + // TODO: remove after 1.12.0 release + contractsToUpgrade = contractsToUpgrade.filter((contract) => contract !== "PaymasterController") + // End of TODO const upgrader = new SkaleManagerUpgrader( "1.11.0", skaleManager, - await prepareContractsList(skaleManager) + contractsToUpgrade ); await upgrader.upgrade(); } diff --git a/package.json b/package.json index b09043724..0d3fa0390 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ } ], "scripts": { - "compile": "npx hardhat clean && npx hardhat compile", + "compile": "npx hardhat compile", + "cleanCompile": "npx hardhat clean && yarn compile", "docs": "scripts/prepare-docs.sh", "fullCheck": "yarn lint && yarn tsc && yarn eslint && yarn cspell && yarn slither", "hooks": "git config core.hooksPath .githooks || true", @@ -44,13 +45,16 @@ "@openzeppelin/contracts": "^4.9.3", "@openzeppelin/contracts-upgradeable": "^4.9.6", "@openzeppelin/hardhat-upgrades": "^3.2.0", - "@skalenetwork/skale-manager-interfaces": "3.1.0", + "@skalenetwork/ima-interfaces": "2.0.0-develop.67", + "@skalenetwork/marionette-interfaces": "^0.0.0-main.6", + "@skalenetwork/paymaster-interfaces": "^1.0.0-main.10", + "@skalenetwork/skale-manager-interfaces": "3.2.0-develop.0", "@skalenetwork/upgrade-tools": "^3.0.0-linter.42", "@typechain/hardhat": "^9.1.0", "dotenv": "^16.3.1", "ethereumjs-util": "^7.1.5", "ethers": "^6.13.1", - "hardhat": "^2.22.5" + "hardhat": "^2.22.8" }, "devDependencies": { "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", @@ -79,7 +83,7 @@ "ethereum-waffle": "^3.4.4", "ganache": "^7.9.1", "hardhat-dependency-compiler": "^1.2.1", - "solhint": "5.0.1", + "solhint": "^5.0.3", "solidity-coverage": "^0.8.4", "solidity-docgen": "^0.5.17", "ts-generator": "^0.1.1", diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 61cce5d71..6bdff3f80 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -1 +1 @@ -slither-analyzer==0.8.3 +slither-analyzer==0.10.3 diff --git a/scripts/test_upgrade.sh b/scripts/test_upgrade.sh index 0ac4a9255..7c8c218a2 100755 --- a/scripts/test_upgrade.sh +++ b/scripts/test_upgrade.sh @@ -53,6 +53,14 @@ rm -r --interactive=never $DEPLOYED_DIR # TODO: use contracts.json file when deployed version starts supporting it # SKALE_MANAGER_ADDRESS=$(cat data/$CONTRACTS_FILENAME | jq -r .SkaleManager) SKALE_MANAGER_ADDRESS=$(cat data/$ABI_FILENAME | jq -r .skale_manager_address) -ALLOW_NOT_ATOMIC_UPGRADE="OK" TARGET="$SKALE_MANAGER_ADDRESS" npx hardhat run migrations/upgrade.ts --network localhost +export ALLOW_NOT_ATOMIC_UPGRADE="OK" +export TARGET="$SKALE_MANAGER_ADDRESS" +export UPGRADE_ALL=true +# TODO: Remove after release 1.12.0 +export IMA="$SKALE_MANAGER_ADDRESS" +export MARIONETTE="$SKALE_MANAGER_ADDRESS" +export PAYMASTER="$SKALE_MANAGER_ADDRESS" +# End of TODO +npx hardhat run migrations/upgrade.ts --network localhost npx ganache instances stop $GANACHE_SESSION diff --git a/slither.config.json b/slither.config.json index b91030d04..69ab44d09 100644 --- a/slither.config.json +++ b/slither.config.json @@ -1,4 +1,4 @@ { - "detectors_to_exclude": "similar-names,reentrancy-events,solc-version,assembly,timestamp,calls-loop,reentrancy-no-eth,public-mappings-nested,incorrect-equality,dead-code", - "filter_paths": "@openzeppelin/contracts/|@openzeppelin/contracts-upgradeable/|thirdparty|test" + "detectors_to_exclude": "similar-names,reentrancy-events,solc-version,assembly,timestamp,calls-loop,reentrancy-no-eth,public-mappings-nested,incorrect-equality,dead-code,pragma", + "filter_paths": "(node_modules/|contracts/hardhat-dependency-compiler/|thirdparty/|test/)" } diff --git a/test/NodesData.ts b/test/NodesData.ts index 527fd325d..cc9d2b636 100644 --- a/test/NodesData.ts +++ b/test/NodesData.ts @@ -190,7 +190,8 @@ describe("NodesData", () => { it("should not modify node domain name by hacker", async () => { await nodes.connect(hacker).setDomainName(0, "new.domain.name") - .should.be.eventually.rejectedWith("Validator address does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorAddressDoesNotExist") + .withArgs(hacker); }); // it("should get array of ips of active nodes", async () => { @@ -330,9 +331,13 @@ describe("NodesData", () => { await nodes.initExit(0); status = await nodes.getNodeStatus(0); assert.equal(status, 1n); - await nodes.setNodeInMaintenance(0).should.be.eventually.rejectedWith("Node is not Active"); + await nodes.setNodeInMaintenance(0) + .should.be.revertedWithCustomError(nodes, "NodeIsNotActive") + .withArgs(0); await nodes.completeExit(0); - await nodes.setNodeInMaintenance(0).should.be.eventually.rejectedWith("Node is not Active"); + await nodes.setNodeInMaintenance(0) + .should.be.revertedWithCustomError(nodes, "NodeIsNotActive") + .withArgs(0); }); it("should decrease number of active nodes after setting node in maintenance", async () => { diff --git a/test/NodesFunctionality.ts b/test/NodesFunctionality.ts index d39084947..689b493d8 100644 --- a/test/NodesFunctionality.ts +++ b/test/NodesFunctionality.ts @@ -81,7 +81,8 @@ describe("NodesFunctionality", () => { publicKey: getPublicKey(nodeAddress), name: "D2", domainName: "some.domain.name" - }).should.be.eventually.rejectedWith("IP address is zero or is not available"); + }).should.be.revertedWithCustomError(nodes, "IpIsNotAvailable") + .withArgs("0x00000000"); }); it("should fail to create node if port is zero", async () => { @@ -95,7 +96,7 @@ describe("NodesFunctionality", () => { publicKey: getPublicKey(nodeAddress), name: "D2", domainName: "some.domain.name" - }).should.be.eventually.rejectedWith("Port is zero"); + }).should.be.revertedWithCustomError(nodes, "PortIsNotSet"); }); it("should fail to create node if public Key is incorrect", async () => { @@ -109,7 +110,8 @@ describe("NodesFunctionality", () => { publicKey: getPublicKey(nodeAddress), name: "D2", domainName: "some.domain.name" - }).should.be.eventually.rejectedWith("Public Key is incorrect"); + }).should.be.revertedWithCustomError(nodes, "PublicKeyIsIncorrect") + .withArgs(getPublicKey(nodeAddress)); }); it("should create node", async () => { @@ -151,7 +153,8 @@ describe("NodesFunctionality", () => { it("should fail to delete non active node", async () => { await nodes.completeExit(0) - .should.be.eventually.rejectedWith("Node is not Leaving"); + .should.be.revertedWithCustomError(nodes, "NodeIsNotLeaving") + .withArgs(0); }); it("should delete node", async () => { @@ -169,7 +172,8 @@ describe("NodesFunctionality", () => { it("should complete exiting", async () => { await nodes.completeExit(0) - .should.be.eventually.rejectedWith("Node is not Leaving"); + .should.be.revertedWithCustomError(nodes, "NodeIsNotLeaving") + .withArgs(0); await nodes.initExit(0); @@ -178,9 +182,15 @@ describe("NodesFunctionality", () => { it("should change IP", async () => { await nodes.connect(holder).changeIP(0, "0x7f000001", "0x00000000").should.be.eventually.rejectedWith("Caller is not an admin"); - await nodes.connect(owner).changeIP(0, "0x7f000001", "0x00000000").should.be.eventually.rejectedWith("IP address is zero or is not available"); - await nodes.connect(owner).changeIP(0, "0x00000000", "0x00000000").should.be.eventually.rejectedWith("IP address is zero or is not available"); - await nodes.connect(owner).changeIP(0, "0x7f000002", "0x7f000001").should.be.eventually.rejectedWith("IP address is not the same"); + await nodes.connect(owner).changeIP(0, "0x7f000001", "0x00000000") + .should.be.revertedWithCustomError(nodes, "IpIsNotAvailable") + .withArgs("0x7f000001"); + await nodes.connect(owner).changeIP(0, "0x00000000", "0x00000000") + .should.be.revertedWithCustomError(nodes, "IpIsNotAvailable") + .withArgs("0x00000000"); + await nodes.connect(owner).changeIP(0, "0x7f000002", "0x7f000001") + .should.be.revertedWithCustomError(nodes, "IpAndPublicIpIsDifferent") + .withArgs("0x7f000002", "0x7f000001"); expect(await nodes.getNodeIP(0)).to.equal("0x7f000001"); expect(await nodes.nodesIPCheck("0x7f000001")).to.equal(true); expect(await nodes.nodesIPCheck("0x7f000002")).to.equal(false); @@ -210,7 +220,8 @@ describe("NodesFunctionality", () => { it("should mark node as incompliant", async () => { await nodes.setNodeIncompliant(nodeId) - .should.be.eventually.rejectedWith("COMPLIANCE_ROLE is required"); + .should.be.revertedWithCustomError(nodes, "RoleRequired") + .withArgs(await nodes.COMPLIANCE_ROLE()); await nodes.grantRole(await nodes.COMPLIANCE_ROLE(), owner.address); (await nodes.incompliant(nodeId)).should.be.equal(false); @@ -282,7 +293,8 @@ describe("NodesFunctionality", () => { it("should complete exiting from first node", async () => { await nodes.completeExit(0) - .should.be.eventually.rejectedWith("Node is not Leaving"); + .should.be.revertedWithCustomError(nodes, "NodeIsNotLeaving") + .withArgs(0); await nodes.initExit(0); @@ -291,7 +303,8 @@ describe("NodesFunctionality", () => { it("should complete exiting from second node", async () => { await nodes.completeExit(1) - .should.be.eventually.rejectedWith("Node is not Leaving"); + .should.be.revertedWithCustomError(nodes, "NodeIsNotLeaving") + .withArgs(1); await nodes.initExit(1); @@ -300,15 +313,31 @@ describe("NodesFunctionality", () => { it("should change IP", async () => { await nodes.connect(holder).changeIP(0, "0x7f000001", "0x00000000").should.be.eventually.rejectedWith("Caller is not an admin"); - await nodes.connect(owner).changeIP(0, "0x7f000001", "0x00000000").should.be.eventually.rejectedWith("IP address is zero or is not available"); - await nodes.connect(owner).changeIP(0, "0x00000000", "0x00000000").should.be.eventually.rejectedWith("IP address is zero or is not available"); - await nodes.connect(owner).changeIP(0, "0x7f000002", "0x00000000").should.be.eventually.rejectedWith("IP address is zero or is not available"); - await nodes.connect(owner).changeIP(0, "0x7f000003", "0x7f000002").should.be.eventually.rejectedWith("IP address is not the same"); + await nodes.connect(owner).changeIP(0, "0x7f000001", "0x00000000") + .should.be.revertedWithCustomError(nodes, "IpIsNotAvailable") + .withArgs("0x7f000001"); + await nodes.connect(owner).changeIP(0, "0x00000000", "0x00000000") + .should.be.revertedWithCustomError(nodes, "IpIsNotAvailable") + .withArgs("0x00000000"); + await nodes.connect(owner).changeIP(0, "0x7f000002", "0x00000000") + .should.be.revertedWithCustomError(nodes, "IpIsNotAvailable") + .withArgs("0x7f000002"); + await nodes.connect(owner).changeIP(0, "0x7f000003", "0x7f000002") + .should.be.revertedWithCustomError(nodes, "IpAndPublicIpIsDifferent") + .withArgs("0x7f000003", "0x7f000002"); await nodes.connect(holder).changeIP(1, "0x7f000002", "0x00000000").should.be.eventually.rejectedWith("Caller is not an admin"); - await nodes.connect(owner).changeIP(1, "0x7f000002", "0x00000000").should.be.eventually.rejectedWith("IP address is zero or is not available"); - await nodes.connect(owner).changeIP(1, "0x00000000", "0x00000000").should.be.eventually.rejectedWith("IP address is zero or is not available"); - await nodes.connect(owner).changeIP(1, "0x7f000001", "0x00000000").should.be.eventually.rejectedWith("IP address is zero or is not available"); - await nodes.connect(owner).changeIP(0, "0x7f000004", "0x7f000002").should.be.eventually.rejectedWith("IP address is not the same"); + await nodes.connect(owner).changeIP(1, "0x7f000002", "0x00000000") + .should.be.revertedWithCustomError(nodes, "IpIsNotAvailable") + .withArgs("0x7f000002"); + await nodes.connect(owner).changeIP(1, "0x00000000", "0x00000000") + .should.be.revertedWithCustomError(nodes, "IpIsNotAvailable") + .withArgs("0x00000000"); + await nodes.connect(owner).changeIP(1, "0x7f000001", "0x00000000") + .should.be.revertedWithCustomError(nodes, "IpIsNotAvailable") + .withArgs("0x7f000001"); + await nodes.connect(owner).changeIP(0, "0x7f000004", "0x7f000002") + .should.be.revertedWithCustomError(nodes, "IpAndPublicIpIsDifferent") + .withArgs("0x7f000004", "0x7f000002"); expect(await nodes.getNodeIP(0)).to.equal("0x7f000001"); expect(await nodes.nodesIPCheck("0x7f000001")).to.equal(true); expect(await nodes.nodesIPCheck("0x7f000002")).to.equal(true); @@ -371,7 +400,7 @@ describe("NodesFunctionality", () => { await delegationController.connect(validator).acceptPendingDelegation(delegationId); await nodes.checkPossibilityCreatingNode(nodeAddress.address) - .should.be.eventually.rejectedWith("Validator must meet the Minimum Staking Requirement"); + .should.be.revertedWithCustomError(nodes, "MinimumStakingRequirementIsNotMet"); }); it("should allow to create node if new epoch is started", async () => { @@ -382,7 +411,7 @@ describe("NodesFunctionality", () => { await nextMonth(contractManager); await nodes.checkPossibilityCreatingNode(nodeAddress.address) - .should.be.eventually.rejectedWith("Validator must meet the Minimum Staking Requirement"); + .should.be.revertedWithCustomError(nodes, "MinimumStakingRequirementIsNotMet"); await constantsHolder.setMSR(amount); @@ -416,7 +445,7 @@ describe("NodesFunctionality", () => { await nextMonth(contractManager); await nodes.checkPossibilityCreatingNode(nodeAddress.address) - .should.be.eventually.rejectedWith("Validator must meet the Minimum Staking Requirement"); + .should.be.revertedWithCustomError(nodes, "MinimumStakingRequirementIsNotMet"); await constantsHolder.setMSR(amount); diff --git a/test/Pricing.ts b/test/Pricing.ts deleted file mode 100644 index e379cc727..000000000 --- a/test/Pricing.ts +++ /dev/null @@ -1,324 +0,0 @@ -import {Wallet} from "ethers"; -import * as chai from "chai"; -import chaiAsPromised from "chai-as-promised"; - -import {ContractManager, - Nodes, - Pricing, - SchainsInternal, - ValidatorService, - ConstantsHolder, - NodeRotation} from "../typechain-types"; - -import {privateKeys} from "./tools/private-keys"; - -import {deployContractManager} from "./tools/deploy/contractManager"; -import {deployNodes} from "./tools/deploy/nodes"; -import {deployPricing} from "./tools/deploy/pricing"; -import {deploySchainsInternal} from "./tools/deploy/schainsInternal"; -import {skipTime, currentTime} from "./tools/time"; -import {deployValidatorService} from "./tools/deploy/delegation/validatorService"; -import {deploySchains} from "./tools/deploy/schains"; -import {deployConstantsHolder} from "./tools/deploy/constantsHolder"; -import {deployNodeRotation} from "./tools/deploy/nodeRotation"; -import {deploySkaleManagerMock} from "./tools/deploy/test/skaleManagerMock"; -import {ethers} from "hardhat"; -import {SignerWithAddress} from "@nomicfoundation/hardhat-ethers/signers"; -import {getPublicKey, getValidatorIdSignature} from "./tools/signatures"; -import {stringKeccak256} from "./tools/hashes"; -import {fastBeforeEach} from "./tools/mocha"; - -chai.should(); -chai.use(chaiAsPromised); - -describe("Pricing", () => { - let owner: SignerWithAddress; - let holder: SignerWithAddress; - let validator: SignerWithAddress; - let nodeAddress1: Wallet; - let nodeAddress2: Wallet; - let nodeAddress3: Wallet; - let nodeAddress4: Wallet; - let nodeAddress5: Wallet; - - let contractManager: ContractManager; - let pricing: Pricing; - let schainsInternal: SchainsInternal; - let nodes: Nodes; - let validatorService: ValidatorService; - let constants: ConstantsHolder; - let nodeRotation: NodeRotation; - - fastBeforeEach(async () => { - [owner, holder, validator] = await ethers.getSigners(); - - nodeAddress1 = new Wallet(String(privateKeys[0])).connect(ethers.provider); - nodeAddress2 = new Wallet(String(privateKeys[1])).connect(ethers.provider); - nodeAddress3 = new Wallet(String(privateKeys[2])).connect(ethers.provider); - nodeAddress4 = new Wallet(String(privateKeys[3])).connect(ethers.provider); - nodeAddress5 = new Wallet(String(privateKeys[4])).connect(ethers.provider); - - - contractManager = await deployContractManager(); - - nodes = await deployNodes(contractManager); - schainsInternal = await deploySchainsInternal(contractManager); - await deploySchains(contractManager); - pricing = await deployPricing(contractManager); - validatorService = await deployValidatorService(contractManager); - constants = await deployConstantsHolder(contractManager); - nodeRotation = await deployNodeRotation(contractManager); - - const skaleManagerMock = await deploySkaleManagerMock(contractManager); - await contractManager.setContractsAddress("SkaleManager", skaleManagerMock); - - await validatorService.connect(validator).registerValidator("Validator", "D2", 0, 0); - const validatorIndex = await validatorService.getValidatorId(validator.address); - const signature1 = await getValidatorIdSignature(validatorIndex, nodeAddress1); - const signature2 = await getValidatorIdSignature(validatorIndex, nodeAddress2); - const signature3 = await getValidatorIdSignature(validatorIndex, nodeAddress3); - const signature4 = await getValidatorIdSignature(validatorIndex, nodeAddress4); - const signature5 = await getValidatorIdSignature(validatorIndex, nodeAddress5); - await validatorService.connect(validator).linkNodeAddress(nodeAddress1.address, signature1); - await validatorService.connect(validator).linkNodeAddress(nodeAddress2.address, signature2); - await validatorService.connect(validator).linkNodeAddress(nodeAddress3.address, signature3); - await validatorService.connect(validator).linkNodeAddress(nodeAddress4.address, signature4); - await validatorService.connect(validator).linkNodeAddress(nodeAddress5.address, signature5); - const NODE_MANAGER_ROLE = await nodes.NODE_MANAGER_ROLE(); - await nodes.grantRole(NODE_MANAGER_ROLE, owner.address); - }); - - describe("on initialized contracts", () => { - fastBeforeEach(async () => { - await schainsInternal.initializeSchain("BobSchain", holder.address, ethers.ZeroAddress, 10, 2); - await schainsInternal.initializeSchain("DavidSchain", holder.address, ethers.ZeroAddress, 10, 4); - await schainsInternal.initializeSchain("JacobSchain", holder.address, ethers.ZeroAddress, 10, 8); - await nodes.createNode( - nodeAddress1.address, - { - port: 8545, - nonce: 0, - ip: "0x7f000001", - publicIp: "0x7f000001", - publicKey: getPublicKey(nodeAddress1), - name: "elvis1", - domainName: "some.domain.name" - }); - - await nodes.createNode( - nodeAddress2.address, - { - port: 8545, - nonce: 0, - ip: "0x7f000003", - publicIp: "0x7f000003", - publicKey: getPublicKey(nodeAddress2), - name: "elvis2", - domainName: "some.domain.name" - }); - - await nodes.createNode( - nodeAddress3.address, - { - port: 8545, - nonce: 0, - ip: "0x7f000005", - publicIp: "0x7f000005", - publicKey: getPublicKey(nodeAddress3), - name: "elvis3", - domainName: "some.domain.name" - }); - - await nodes.createNode( - nodeAddress4.address, - { - port: 8545, - nonce: 0, - ip: "0x7f000007", - publicIp: "0x7f000007", - publicKey: getPublicKey(nodeAddress4), - name: "elvis4", - domainName: "some.domain.name" - }); - }); - - it("should increase number of schains", async () => { - const numberOfSchains = await schainsInternal.numberOfSchains(); - numberOfSchains.should.be.equal(3); - }); - - it("should increase number of nodes", async () => { - const numberOfNodes = await nodes.getNumberOfNodes(); - numberOfNodes.should.be.equal(4); - }); - - describe("on existing nodes and schains", () => { - const bobSchainHash = stringKeccak256("BobSchain"); - const davidSchainHash = stringKeccak256("DavidSchain"); - const jacobSchainHash = stringKeccak256("JacobSchain"); - - fastBeforeEach(async () => { - await schainsInternal.createGroupForSchain(bobSchainHash, 1, 32); - await schainsInternal.createGroupForSchain(davidSchainHash, 1, 32); - await schainsInternal.createGroupForSchain(jacobSchainHash, 2, 128); - }); - - async function getLoadCoefficient() { - const numberOfNodes = await nodes.getNumberOfNodes(); - let sumNode = 0; - for (let i = 0; i < numberOfNodes; i++) { - if (await nodes.isNodeActive(i)) { - const getActiveSchains = await schainsInternal.getActiveSchains(i); - for (const schain of getActiveSchains) { - const partOfNode = await schainsInternal.getSchainsPartOfNode(schain); - const isNodeLeft = await nodes.isNodeLeft(i); - if (partOfNode !== 0n && !isNodeLeft) { - sumNode += Number(partOfNode); - } - } - } - } - return sumNode / (128 * Number(await nodes.getNumberOnlineNodes())); - } - - it("should check load percentage of network", async () => { - const newLoadPercentage = Math.floor(await getLoadCoefficient() * 100); - const loadPercentage = await pricing.getTotalLoadPercentage(); - loadPercentage.should.be.equal(newLoadPercentage); - }); - - it("should check total number of nodes", async () => { - await pricing.initNodes(); - const totalNodes = await pricing.totalNodes(); - totalNodes.should.be.equal(4); - }); - - it("should not change price when no any new nodes have been added", async () => { - await pricing.initNodes(); - await skipTime(61); - await pricing.adjustPrice() - .should.be.eventually.rejectedWith("No changes to node supply"); - }); - - it("should not change price when the price is updated more often than necessary", async () => { - await pricing.initNodes(); - await pricing.adjustPrice() - .should.be.eventually.rejectedWith("It's not a time to update a price"); - }); - - describe("change price when changing the number of nodes", () => { - let oldPrice: bigint; - let lastUpdated: bigint; - - fastBeforeEach(async () => { - await pricing.initNodes(); - oldPrice = await pricing.price(); - lastUpdated = await pricing.lastUpdated(); - }); - - async function getPrice(secondSincePreviousUpdate: bigint) { - const MIN_PRICE = Number(await constants.MIN_PRICE()); - const ADJUSTMENT_SPEED = Number(await constants.ADJUSTMENT_SPEED()); - const OPTIMAL_LOAD_PERCENTAGE = Number(await constants.OPTIMAL_LOAD_PERCENTAGE()); - const COOLDOWN_TIME = Number(await constants.COOLDOWN_TIME()); - - const priceChangeSpeed = ADJUSTMENT_SPEED * Number(oldPrice) / MIN_PRICE * - (await getLoadCoefficient() * 100 - OPTIMAL_LOAD_PERCENTAGE); - let price = Number(oldPrice) + priceChangeSpeed * Number(secondSincePreviousUpdate) / COOLDOWN_TIME; - if (price < MIN_PRICE) { - price = MIN_PRICE; - } - return BigInt(Math.floor(price)); - } - - it("should change price when new active node has been added", async () => { - await nodes.createNode( - nodeAddress5.address, - { - port: 8545, - nonce: 0, - ip: "0x7f000010", - publicIp: "0x7f000011", - publicKey: getPublicKey(nodeAddress5), - name: "vadim", - domainName: "some.domain.name" - }); - const MINUTES_PASSED = 2n; - await skipTime(lastUpdated + MINUTES_PASSED * 60n - BigInt(await currentTime())); - - await pricing.adjustPrice(); - const receivedPrice = await pricing.price(); - - const correctPrice = await getPrice(await pricing.lastUpdated() - lastUpdated); - - receivedPrice.should.be.equal(correctPrice); - oldPrice.should.be.above(receivedPrice); - }); - - it("should change price when active node has been removed", async () => { - // search non full node to rotate - let nodeToExit = -1; - let numberOfSchains = 0; - for (let i = 0; i < await nodes.getNumberOfNodes(); i++) { - if (await nodes.isNodeActive(i)) { - const getActiveSchains = await schainsInternal.getActiveSchains(i); - let totalPartOfNode = 0n; - numberOfSchains = 0; - for (const schain of getActiveSchains) { - const partOfNode = await schainsInternal.getSchainsPartOfNode(schain); - ++numberOfSchains; - totalPartOfNode += partOfNode; - } - if (totalPartOfNode < 100) { - nodeToExit = i; - break; - } - } - } - - await nodes.initExit(nodeToExit); - for(let i = 0; i < numberOfSchains; ++i) { - await nodeRotation.exitFromSchain(nodeToExit); - } - await nodes.completeExit(nodeToExit); - - const MINUTES_PASSED = 2n; - await skipTime(lastUpdated + MINUTES_PASSED * 60n - BigInt(await currentTime())); - - await pricing.adjustPrice(); - const receivedPrice = await pricing.price(); - - const correctPrice = await getPrice(await pricing.lastUpdated() - lastUpdated); - - receivedPrice.should.be.equal(correctPrice); - oldPrice.should.be.below(receivedPrice); - }); - - it("should set price to min of too many minutes passed and price is less than min", async () => { - await nodes.createNode( - nodeAddress5.address, - { - port: 8545, - nonce: 0, - ip: "0x7f000010", - publicIp: "0x7f000011", - publicKey: getPublicKey(nodeAddress5), - name: "vadim", - domainName: "some.domain.name" - }); - - const MINUTES_PASSED = 30n; - await skipTime(lastUpdated + MINUTES_PASSED * 60n - BigInt(await currentTime())); - - await pricing.adjustPrice(); - const receivedPrice = await pricing.price(); - - const correctPrice = await getPrice(await pricing.lastUpdated() - lastUpdated); - - receivedPrice.should.be.equal(correctPrice); - oldPrice.should.be.above(receivedPrice); - }); - }); - }); - }); -}); diff --git a/test/Schains.ts b/test/Schains.ts index d03230b8e..5c93cda4e 100644 --- a/test/Schains.ts +++ b/test/Schains.ts @@ -127,12 +127,13 @@ describe("Schains", () => { options: [] }] ) - ).should.be.eventually.rejectedWith("Not enough money to create Schain"); + ).should.be.revertedWithCustomError(schains, "NotEnoughFunds"); }); it("should not allow everyone to create schains as the foundation", async () => { await schains.addSchainByFoundation(5, SchainType.SMALL, 0, "d2", ethers.ZeroAddress, ethers.ZeroAddress, []) - .should.be.eventually.rejectedWith("Sender is not authorized to create schain"); + .should.be.revertedWithCustomError(schains, "RoleRequired") + .withArgs(await schains.SCHAIN_CREATOR_ROLE()); }) it("should fail when schain type is wrong", async () => { @@ -177,7 +178,8 @@ describe("Schains", () => { options: [] }] ) - ).should.be.eventually.rejectedWith("Schain name is not available"); + ).should.be.revertedWithCustomError(schains, "SchainNameIsNotAvailable") + .withArgs("Mainnet"); }); it("should fail when schain name is None", async () => { @@ -196,7 +198,8 @@ describe("Schains", () => { options: [] }] ) - ).should.be.eventually.rejectedWith("Schain name is not available"); + ).should.be.revertedWithCustomError(schains, "SchainNameIsNotAvailable") + .withArgs(""); }); it("should fail when nodes count is too low", async () => { @@ -1079,7 +1082,8 @@ describe("Schains", () => { await schainsInternal.getSchains().should.be.eventually.empty; await schains.getOption(schainHash, "one") - .should.be.eventually.rejectedWith("The schain does not exist"); + .should.be.revertedWithCustomError(schains, "SchainDoesNotExist") + .withArgs(schainHash); }); it("should allow the foundation to create schain without tokens", async () => { @@ -1491,7 +1495,8 @@ describe("Schains", () => { options: [] }] ) - ).should.be.eventually.rejectedWith("Schain name is not available"); + ).should.be.revertedWithCustomError(schains, "SchainNameIsNotAvailable") + .withArgs("D2"); }); it("should be able to delete schain", async () => { @@ -1518,7 +1523,7 @@ describe("Schains", () => { await schains.deleteSchain( nodeAddress1.address, "D2", - ).should.be.eventually.rejectedWith("Message sender is not the owner of the Schain"); + ).should.be.revertedWithCustomError(schains, "SenderIsNotTheOwnerOfTheSchain"); }); }); @@ -1558,7 +1563,8 @@ describe("Schains", () => { options: [] }] ) - ).should.be.eventually.rejectedWith("Schain name is not available"); + ).should.be.revertedWithCustomError(schains, "SchainNameIsNotAvailable") + .withArgs("D2"); }); it("should be able to delete schain", async () => { @@ -1573,7 +1579,7 @@ describe("Schains", () => { await schains.deleteSchain( nodeAddress1.address, "D2", - ).should.be.eventually.rejectedWith("Message sender is not the owner of the Schain"); + ).should.be.revertedWithCustomError(schains, "SenderIsNotTheOwnerOfTheSchain"); }); }); }); @@ -1697,7 +1703,8 @@ describe("Schains", () => { it("should reject initExit if node in maintenance", async () => { await nodes.setNodeInMaintenance(0); - await nodes.initExit(0).should.be.eventually.rejectedWith("Node should be Active"); + await nodes.initExit(0).should.be.revertedWithCustomError(nodes, "NodeIsNotActive") + .withArgs(0); }); it("should rotate 2 nodes consistently", async () => { @@ -1957,7 +1964,8 @@ describe("Schains", () => { options: [] }] ) - ).should.be.eventually.rejectedWith("Schain name is not available"); + ).should.be.revertedWithCustomError(schains, "SchainNameIsNotAvailable") + .withArgs("d2"); schainNameAvailable = await schainsInternal.isSchainNameAvailable("d3"); assert.equal(schainNameAvailable, false); await schains.addSchain( @@ -1974,7 +1982,8 @@ describe("Schains", () => { options: [] }] ) - ).should.be.eventually.rejectedWith("Schain name is not available"); + ).should.be.revertedWithCustomError(schains, "SchainNameIsNotAvailable") + .withArgs("d3"); schainNameAvailable = await schainsInternal.isSchainNameAvailable("d4"); assert.equal(schainNameAvailable, true); await schains.addSchain( @@ -2626,8 +2635,9 @@ describe("Schains", () => { if (!(await nodes.isNodeLeft(rotIndex))) { await skaleManager.connect(nodeAddress2).nodeExit(rotIndex); } - await validatorService.getValidatorIdByNodeAddress(nodeAddress2.address) - .should.be.eventually.rejectedWith("Node address is not assigned to a validator"); + await validatorService.getValidatorIdByNodeAddress(nodeAddress2) + .should.be.revertedWithCustomError(validatorService, "NodeAddressIsNotAssignedToValidator") + .withArgs(nodeAddress2); await schainsInternal.getActiveSchains(rotIndex).should.be.eventually.empty; }); @@ -2645,7 +2655,8 @@ describe("Schains", () => { await skaleManager.connect(validator).nodeExit(rotatedNodeIndex); } await validatorService.getValidatorIdByNodeAddress(nodeAddress2.address) - .should.be.eventually.rejectedWith("Node address is not assigned to a validator"); + .should.be.revertedWithCustomError(validatorService, "NodeAddressIsNotAssignedToValidator") + .withArgs(nodeAddress2); await schainsInternal.getActiveSchains(rotatedNodeIndex).should.be.eventually.empty; }); @@ -2663,7 +2674,8 @@ describe("Schains", () => { await skaleManager.nodeExit(rotatedNodeIndex); } await validatorService.getValidatorIdByNodeAddress(nodeAddress2.address) - .should.be.eventually.rejectedWith("Node address is not assigned to a validator"); + .should.be.revertedWithCustomError(validatorService, "NodeAddressIsNotAssignedToValidator") + .withArgs(nodeAddress2); await schainsInternal.getActiveSchains(rotatedNodeIndex).should.be.eventually.empty; }); @@ -2683,7 +2695,8 @@ describe("Schains", () => { await skaleManager.connect(nodeAddress3).nodeExit(rotIndex); } await validatorService.getValidatorIdByNodeAddress(nodeAddress3.address) - .should.be.eventually.rejectedWith("Node address is not assigned to a validator"); + .should.be.revertedWithCustomError(validatorService, "NodeAddressIsNotAssignedToValidator") + .withArgs(nodeAddress3); await schainsInternal.getActiveSchains(rotIndex).should.be.eventually.empty; }); diff --git a/test/SkaleManager.ts b/test/SkaleManager.ts index 0531965f5..3fbaf2852 100644 --- a/test/SkaleManager.ts +++ b/test/SkaleManager.ts @@ -205,7 +205,9 @@ describe("SkaleManager", () => { "0x7f000001", // public ip getPublicKey(nodeAddress), // public key "d2", // name - "some.domain.name").should.be.eventually.rejectedWith("Validator is not authorized to create a node"); + "some.domain.name") + .should.be.revertedWithCustomError(validatorService, "ValidatorIsNotAuthorized") + .withArgs(validatorId); await validatorService.enableValidator(validatorId); await skaleManager.connect(nodeAddress).createNode( 8545, // port @@ -238,8 +240,9 @@ describe("SkaleManager", () => { it("should reject if node in maintenance call nodeExit", async () => { await nodesContract.setNodeInMaintenance(0); - await nodesContract.initExit(0).should.be.eventually.rejectedWith("Node should be Active"); - // await skaleManager.connect(nodeAddress).nodeExit(0).should.be.eventually.rejectedWith("Node should be Leaving"); + await nodesContract.initExit(0) + .should.be.revertedWithCustomError(nodesContract, "NodeIsNotActive") + .withArgs(0); }); it("should be Left if there is no schains and node has exited", async () => { @@ -384,14 +387,16 @@ describe("SkaleManager", () => { it("should fail to initiate exiting of first node from another account", async () => { await nodesContract.connect(hacker).initExit(0) - .should.be.eventually.rejectedWith("NODE_MANAGER_ROLE is required"); + .should.be.revertedWithCustomError(nodesContract, "RoleRequired") + .withArgs(await nodesContract.NODE_MANAGER_ROLE()); await skaleManager.connect(hacker).nodeExit(0) .should.be.eventually.rejectedWith("Sender is not permitted to call this function"); }); it("should fail to initiate exiting of second node from another account", async () => { await nodesContract.connect(hacker).initExit(1) - .should.be.eventually.rejectedWith("NODE_MANAGER_ROLE is required"); + .should.be.revertedWithCustomError(nodesContract, "RoleRequired") + .withArgs(await nodesContract.NODE_MANAGER_ROLE()); await skaleManager.connect(hacker).nodeExit(1) .should.be.eventually.rejectedWith("Sender is not permitted to call this function"); }); @@ -442,7 +447,8 @@ describe("SkaleManager", () => { "0x7f000001", // public ip getPublicKey(nodeAddress), // public key "d2", // name - "some.domain.name").should.be.eventually.rejectedWith("Validator must meet the Minimum Staking Requirement"); + "some.domain.name" + ).should.be.revertedWithCustomError(nodesContract, "MinimumStakingRequirementIsNotMet"); }); describe("when developer has SKALE tokens", () => { @@ -488,7 +494,7 @@ describe("SkaleManager", () => { options: [] }] ) - ).should.be.eventually.rejectedWith("Minimal schain lifetime should be satisfied"); + ).should.be.revertedWithCustomError(schains, "SchainLifetimeIsTooSmall"); await constantsHolder.setMinimalSchainLifetime(4); await skaleToken.connect(developer).send( @@ -529,7 +535,7 @@ describe("SkaleManager", () => { options: [] }] ) - ).should.be.eventually.rejectedWith("It is not a time for creating Schain"); + ).should.be.revertedWithCustomError(schains, "SchainIsCreatedTooEarly"); }); describe("when schain is created", () => { @@ -556,7 +562,7 @@ describe("SkaleManager", () => { it("should fail to delete schain if sender is not owner of it", async () => { await skaleManager.connect(hacker).deleteSchain("d2") - .should.be.eventually.rejectedWith("Message sender is not the owner of the Schain"); + .should.be.revertedWithCustomError(schains, "SenderIsNotTheOwnerOfTheSchain"); }); it("should delete schain", async () => { @@ -595,7 +601,7 @@ describe("SkaleManager", () => { it("should fail to delete schain if sender is not owner of it", async () => { await skaleManager.connect(hacker).deleteSchain("d3") - .should.be.eventually.rejectedWith("Message sender is not the owner of the Schain"); + .should.be.revertedWithCustomError(schains, "SenderIsNotTheOwnerOfTheSchain"); }); it("should delete schain by root", async () => { diff --git a/test/Wallets.ts b/test/Wallets.ts index 0f7e311e5..a5d2be001 100644 --- a/test/Wallets.ts +++ b/test/Wallets.ts @@ -126,7 +126,8 @@ describe("Wallets", () => { it("should revert if someone sends ETH to contract Wallets", async() => { const amount = ethers.parseEther("1.0"); await owner.sendTransaction({to: wallets, value: amount}) - .should.be.eventually.rejectedWith("Validator address does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorAddressDoesNotExist") + .withArgs(owner); }); it("should recharge validator wallet sending ETH to contract Wallets", async() => { @@ -155,7 +156,9 @@ describe("Wallets", () => { const validator1BalanceAfterWithdraw = await ethers.provider.getBalance(validator1); validator1BalanceAfterWithdraw.should.be.equal(validator1Balance + amount - await ethSpent(tx)); await wallets.connect(validator2).withdrawFundsFromValidatorWallet(amount).should.be.eventually.rejectedWith("Balance is too low"); - await wallets.withdrawFundsFromValidatorWallet(amount).should.be.eventually.rejectedWith("Validator address does not exist"); + await wallets.withdrawFundsFromValidatorWallet(amount) + .should.be.revertedWithCustomError(validatorService, "ValidatorAddressDoesNotExist") + .withArgs(owner); }); describe("when nodes and schains have been created", () => { diff --git a/test/delegation/Delegation.ts b/test/delegation/Delegation.ts index 49ce02231..3f721a760 100644 --- a/test/delegation/Delegation.ts +++ b/test/delegation/Delegation.ts @@ -370,7 +370,8 @@ describe("Delegation", () => { it("should not allow holder to delegate to unregistered validator", async () => { await delegationController.connect(holder1).delegate(13, 1, 2, "D2 is even") - .should.be.eventually.rejectedWith("Validator with such ID does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorDoesNotExist") + .withArgs(13); }); it("should calculate bond amount if validator delegated to itself", async () => { diff --git a/test/delegation/DelegationController.ts b/test/delegation/DelegationController.ts index 063c552fc..c18749751 100644 --- a/test/delegation/DelegationController.ts +++ b/test/delegation/DelegationController.ts @@ -91,13 +91,15 @@ describe("DelegationController", () => { it("should reject delegation if validator with such id does not exist", async () => { const nonExistedValidatorId = 2; await delegationController.connect(holder1).delegate(nonExistedValidatorId, amount, delegationPeriod, info) - .should.be.eventually.rejectedWith("Validator with such ID does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorDoesNotExist") + .withArgs(nonExistedValidatorId); }); it("should reject delegation if it doesn't meet minimum delegation amount", async () => { amount = 99; await delegationController.connect(holder1).delegate(validatorId, amount, delegationPeriod, info) - .should.be.eventually.rejectedWith("Amount does not meet the validator's minimum delegation amount"); + .should.be.revertedWithCustomError(validatorService, "AmountDoesNotMeetTheValidatorsMinimumDelegationAmount") + .withArgs(amount, (await validatorService.getValidator(validatorId)).minimumDelegationAmount); }); it("should reject delegation if request doesn't meet allowed delegation period", async () => { @@ -146,7 +148,8 @@ describe("DelegationController", () => { await skaleToken.mint(holder1.address, amount, "0x", "0x"); await validatorService.disableValidator(validatorId); await delegationController.connect(holder1).delegate(validatorId, amount, delegationPeriod, info) - .should.be.eventually.rejectedWith("Validator is not authorized to accept delegation request"); + .should.be.revertedWithCustomError(validatorService, "ValidatorIsNotAuthorized") + .withArgs(validatorId); await validatorService.disableWhitelist(); await delegationController.connect(holder1).delegate(validatorId, amount, delegationPeriod, info); }); @@ -191,7 +194,8 @@ describe("DelegationController", () => { it("should reject accepting request if such validator doesn't exist", async () => { await delegationController.connect(validator2).acceptPendingDelegation(delegationId) - .should.be.rejectedWith("Validator address does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorAddressDoesNotExist") + .withArgs(validator2); }); it("should reject accepting request if validator already canceled it", async () => { diff --git a/test/delegation/ValidatorService.ts b/test/delegation/ValidatorService.ts index 3c7f12efe..4a91229c9 100644 --- a/test/delegation/ValidatorService.ts +++ b/test/delegation/ValidatorService.ts @@ -78,12 +78,14 @@ describe("ValidatorService", () => { "Really good validator", 1500, 100) - .should.be.eventually.rejectedWith("Fee rate of validator should be lower than 100%"); + .should.be.revertedWithCustomError(validatorService, "WrongFeeValue") + .withArgs(1500); }); it("should allow only owner to call disableWhitelist", async() => { await validatorService.connect(validator1).disableWhitelist() - .should.be.eventually.rejectedWith("VALIDATOR_MANAGER_ROLE is required"); + .should.be.revertedWithCustomError(validatorService, "RoleRequired") + .withArgs(await validatorService.VALIDATOR_MANAGER_ROLE()); await validatorService.connect(owner).disableWhitelist(); }); @@ -110,7 +112,8 @@ describe("ValidatorService", () => { "Really good validator", 500, 100) - .should.be.eventually.rejectedWith("Validator with such address already exists"); + .should.be.revertedWithCustomError(validatorService, "AddressIsAlreadyInUse") + .withArgs(validator1); }); it("should reset name, description, minimum delegation amount", async () => { @@ -137,7 +140,8 @@ describe("ValidatorService", () => { const signature = await getValidatorIdSignature(validatorId, nodeAddress); await validatorService.connect(validator1).linkNodeAddress(nodeAddress.address, signature); await validatorService.connect(nodeAddress).unlinkNodeAddress(validator1.address) - .should.be.eventually.rejectedWith("Validator address does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorAddressDoesNotExist") + .withArgs(nodeAddress); }); it("should reject if validator tried to override node address of another validator", async () => { @@ -152,7 +156,8 @@ describe("ValidatorService", () => { const signature2 = await getValidatorIdSignature(validatorId2, nodeAddress); await validatorService.connect(validator1).linkNodeAddress(nodeAddress.address, signature1); await validatorService.connect(validator2).linkNodeAddress(nodeAddress.address, signature2) - .should.be.eventually.rejectedWith("Validator cannot override node address"); + .should.be.revertedWithCustomError(validatorService, "ValidatorCannotOverrideNodeAddress") + .withArgs(validatorId2, nodeAddress); const id = await validatorService.getValidatorIdByNodeAddress(nodeAddress.address); id.should.be.equal(validatorId1); }); @@ -166,7 +171,8 @@ describe("ValidatorService", () => { const validatorId = await validatorService.getValidatorId(validator1.address); const signature = await getValidatorIdSignature(validatorId, validator2); await validatorService.connect(validator1).linkNodeAddress(validator2.address, signature) - .should.be.eventually.rejectedWith("Node address is a validator"); + .should.be.revertedWithCustomError(validatorService, "NodeAddressIsAValidator") + .withArgs(validator2, await validatorService.getValidatorId(validator2)); }); it("should unlink node address for validator", async () => { @@ -179,13 +185,15 @@ describe("ValidatorService", () => { 500, 100); await validatorService.connect(validator2).unlinkNodeAddress(nodeAddress.address) - .should.be.eventually.rejectedWith("Validator does not have permissions to unlink node"); + .should.be.revertedWithCustomError(validatorService, "NoPermissionsToUnlinkNode") + .withArgs(await validatorService.getValidatorId(validator2), nodeAddress); const id = await validatorService.getValidatorIdByNodeAddress(nodeAddress.address); id.should.be.equal(validatorId); await validatorService.connect(validator1).unlinkNodeAddress(nodeAddress.address); await validatorService.connect(validator1).getValidatorId(nodeAddress.address) - .should.be.eventually.rejectedWith("Validator address does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorAddressDoesNotExist") + .withArgs(nodeAddress); }); it("should not allow changing the address to the address of an existing validator", async () => { @@ -195,7 +203,8 @@ describe("ValidatorService", () => { 500, 100); await validatorService.connect(validator2).requestForNewAddress(validator1.address) - .should.be.eventually.rejectedWith("Address already registered"); + .should.be.revertedWithCustomError(validatorService, "AddressIsAlreadyInUse") + .withArgs(validator1); }); describe("when validator requests for a new address", () => { @@ -212,7 +221,8 @@ describe("ValidatorService", () => { it("should reject when hacker tries to change validator address", async () => { const validatorId = 1; await validatorService.connect(validator2).confirmNewAddress(validatorId) - .should.be.eventually.rejectedWith("The validator address cannot be changed because it is not the actual owner"); + .should.be.revertedWithCustomError(validatorService, "SenderHasToBeEqualToRequestedAddress") + .withArgs(validator2, validator3); }); it("should set new address for validator", async () => { @@ -221,28 +231,32 @@ describe("ValidatorService", () => { await validatorService.connect(validator3).confirmNewAddress(validatorId); (await validatorService.getValidatorId(validator3.address)).should.be.equal(validatorId); await validatorService.getValidatorId(validator1.address) - .should.be.eventually.rejectedWith("Validator address does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorAddressDoesNotExist") + .withArgs(validator1); }); }); it("should reject when someone tries to set new address for validator that doesn't exist", async () => { await validatorService.requestForNewAddress(validator2.address) - .should.be.eventually.rejectedWith("Validator address does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorAddressDoesNotExist") + .withArgs(owner); }); it("should reject if validator tries to set new address as null", async () => { await validatorService.requestForNewAddress("0x0000000000000000000000000000000000000000") - .should.be.eventually.rejectedWith("New address cannot be null"); + .should.be.revertedWithCustomError(validatorService, "AddressIsNotSet"); }); it("should reject if provided validatorId equals zero", async () => { await validatorService.enableValidator(0) - .should.be.eventually.rejectedWith("Validator with such ID does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorDoesNotExist") + .withArgs(0); }); it("should allow only VALIDATOR_MANAGER_ROLE to enable validator", async () => { await validatorService.connect(holder).enableValidator(1) - .should.be.eventually.rejectedWith("VALIDATOR_MANAGER_ROLE is required"); + .should.be.revertedWithCustomError(validatorService, "RoleRequired") + .withArgs(await validatorService.VALIDATOR_MANAGER_ROLE()); await deploySkaleManager(contractManager); const VALIDATOR_MANAGER_ROLE = await validatorService.VALIDATOR_MANAGER_ROLE(); await validatorService.grantRole(VALIDATOR_MANAGER_ROLE, holder.address); @@ -252,7 +266,8 @@ describe("ValidatorService", () => { it("should allow only VALIDATOR_MANAGER_ROLE to disable validator", async () => { await validatorService.enableValidator(1); await validatorService.connect(holder).disableValidator(1) - .should.be.eventually.rejectedWith("VALIDATOR_MANAGER_ROLE is required"); + .should.be.revertedWithCustomError(validatorService, "RoleRequired") + .withArgs(await validatorService.VALIDATOR_MANAGER_ROLE()); await deploySkaleManager(contractManager); const VALIDATOR_MANAGER_ROLE = await validatorService.VALIDATOR_MANAGER_ROLE(); await validatorService.grantRole(VALIDATOR_MANAGER_ROLE, holder.address); @@ -308,15 +323,18 @@ describe("ValidatorService", () => { it("should allow to enable validator in whitelist", async () => { await validatorService.connect(validator1).enableValidator(validatorId) - .should.be.eventually.rejectedWith("VALIDATOR_MANAGER_ROLE is required"); + .should.be.revertedWithCustomError(validatorService, "RoleRequired") + .withArgs(await validatorService.VALIDATOR_MANAGER_ROLE()); await validatorService.enableValidator(validatorId); }); it("should allow to disable validator from whitelist", async () => { await validatorService.connect(validator1).disableValidator(validatorId) - .should.be.eventually.rejectedWith("VALIDATOR_MANAGER_ROLE is required"); + .should.be.revertedWithCustomError(validatorService, "RoleRequired") + .withArgs(await validatorService.VALIDATOR_MANAGER_ROLE()); await validatorService.disableValidator(validatorId) - .should.be.eventually.rejectedWith("Validator is already disabled"); + .should.be.revertedWithCustomError(validatorService, "ValidatorIsAlreadyDisabled") + .withArgs(validatorId); await validatorService.enableValidator(validatorId); await validatorService.isAuthorizedValidator(validatorId).should.eventually.be.true; @@ -326,7 +344,8 @@ describe("ValidatorService", () => { it("should not allow to send delegation request if validator isn't authorized", async () => { await delegationController.connect(holder).delegate(validatorId, amount, delegationPeriod, info) - .should.be.eventually.rejectedWith("Validator is not authorized to accept delegation request"); + .should.be.revertedWithCustomError(validatorService, "ValidatorIsNotAuthorized") + .withArgs(validatorId); }); it("should allow to send delegation request if validator is authorized", async () => { @@ -340,11 +359,13 @@ describe("ValidatorService", () => { await delegationController.connect(holder).delegate(validatorId, amount, delegationPeriod, info); await validatorService.connect(holder).stopAcceptingNewRequests() - .should.be.eventually.rejectedWith("Validator address does not exist"); + .should.be.revertedWithCustomError(validatorService, "ValidatorAddressDoesNotExist") + .withArgs(holder); await validatorService.connect(validator1).stopAcceptingNewRequests() await delegationController.connect(holder).delegate(validatorId, amount, delegationPeriod, info) - .should.be.eventually.rejectedWith("The validator is not currently accepting new requests"); + .should.be.revertedWithCustomError(validatorService, "ValidatorIsNotCurrentlyAcceptingNewRequests") + .withArgs(validatorId); await validatorService.connect(validator1).startAcceptingNewRequests(); await delegationController.connect(holder).delegate(validatorId, amount, delegationPeriod, info); diff --git a/test/tools/deploy/delegation/validatorService.ts b/test/tools/deploy/delegation/validatorService.ts index a6ab1a042..46518dcb2 100644 --- a/test/tools/deploy/delegation/validatorService.ts +++ b/test/tools/deploy/delegation/validatorService.ts @@ -1,6 +1,7 @@ import {ContractManager, ValidatorService} from "../../../../typechain-types"; import {deployConstantsHolder} from "../constantsHolder"; import {deployFunctionFactory} from "../factory"; +import {deployPaymasterController} from "../paymasterController"; import {deployDelegationController} from "./delegationController"; const name = "ValidatorService"; @@ -8,6 +9,7 @@ const name = "ValidatorService"; async function deployDependencies(contractManager: ContractManager) { await deployDelegationController(contractManager); await deployConstantsHolder(contractManager); + await deployPaymasterController(contractManager); } export const deployValidatorService = deployFunctionFactory( diff --git a/test/tools/deploy/paymasterController.ts b/test/tools/deploy/paymasterController.ts new file mode 100644 index 000000000..35512009d --- /dev/null +++ b/test/tools/deploy/paymasterController.ts @@ -0,0 +1,21 @@ +import {ethers} from "hardhat"; +import {ContractManager, PaymasterController} from "../../../typechain-types"; +import {deployFunctionFactory} from "./factory"; +import {deployImaMock} from "./test/imaMock"; + +export const deployPaymasterController = deployFunctionFactory( + "PaymasterController", + async (contractManager: ContractManager) => { + const ima = await deployImaMock(contractManager); + + // Initialize + const paymasterControllerFactory = await ethers.getContractFactory("PaymasterController"); + const paymasterController = await paymasterControllerFactory.attach( + await contractManager.getContract("PaymasterController") + ) as unknown as PaymasterController; + await paymasterController.setImaAddress(ima); + await paymasterController.setMarionetteAddress(paymasterController); + await paymasterController.setPaymasterAddress(paymasterController); + await paymasterController.setPaymasterChainHash(ethers.solidityPackedKeccak256(["string"], ["d2"])); + }, +); diff --git a/test/tools/deploy/pricing.ts b/test/tools/deploy/pricing.ts deleted file mode 100644 index f985062a3..000000000 --- a/test/tools/deploy/pricing.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {ContractManager, Pricing} from "../../../typechain-types"; -import {deployFunctionFactory} from "./factory"; -import {deployNodes} from "./nodes"; -import {deploySchainsInternal} from "./schainsInternal"; - -export const deployPricing = deployFunctionFactory( - "Pricing", - async (contractManager: ContractManager) => { - await deployNodes(contractManager); - await deploySchainsInternal(contractManager); - } -); diff --git a/test/tools/deploy/test/imaMock.ts b/test/tools/deploy/test/imaMock.ts new file mode 100644 index 000000000..dc301ec90 --- /dev/null +++ b/test/tools/deploy/test/imaMock.ts @@ -0,0 +1,5 @@ +import {ImaMock} from "../../../../typechain-types"; +import {deployWithConstructorFunctionFactory} from "../factory"; + +export const deployImaMock + = deployWithConstructorFunctionFactory("ImaMock"); diff --git a/yarn.lock b/yarn.lock index ece2f28a1..8e1f94816 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1118,53 +1118,53 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@nomicfoundation/edr-darwin-arm64@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.4.0.tgz#bbb43f0e01f40839b0bd38c2c443cb6910ae955f" - integrity sha512-7+rraFk9tCqvfemv9Ita5vTlSBAeO/S5aDKOgGRgYt0JEKZlrX161nDW6UfzMPxWl9GOLEDUzCEaYuNmXseUlg== +"@nomicfoundation/edr-darwin-arm64@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.5.2.tgz#72f7a826c9f0f2c91308edca562de3b9484ac079" + integrity sha512-Gm4wOPKhbDjGTIRyFA2QUAPfCXA1AHxYOKt3yLSGJkQkdy9a5WW+qtqKeEKHc/+4wpJSLtsGQfpzyIzggFfo/A== -"@nomicfoundation/edr-darwin-x64@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.4.0.tgz#b1ffcd9142418fd8498de34a7336b3f977907c86" - integrity sha512-+Hrc0mP9L6vhICJSfyGo/2taOToy1AIzVZawO3lU8Lf7oDQXfhQ4UkZnkWAs9SVu1eUwHUGGGE0qB8644piYgg== +"@nomicfoundation/edr-darwin-x64@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.5.2.tgz#6d0fedb219d664631c6feddc596ab8c3bbc36fa8" + integrity sha512-ClyABq2dFCsrYEED3/UIO0c7p4H1/4vvlswFlqUyBpOkJccr75qIYvahOSJRM62WgUFRhbSS0OJXFRwc/PwmVg== -"@nomicfoundation/edr-linux-arm64-gnu@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.4.0.tgz#8173d16d4f6f2b3e82ba7096d2a1ea3619d8bfa7" - integrity sha512-4HUDMchNClQrVRfVTqBeSX92hM/3khCgpZkXP52qrnJPqgbdCxosOehlQYZ65wu0b/kaaZSyvACgvCLSQ5oSzQ== +"@nomicfoundation/edr-linux-arm64-gnu@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.5.2.tgz#60e4d52d963141bc2bb4a02639dc590a7fbdda2f" + integrity sha512-HWMTVk1iOabfvU2RvrKLDgtFjJZTC42CpHiw2h6rfpsgRqMahvIlx2jdjWYzFNy1jZKPTN1AStQ/91MRrg5KnA== -"@nomicfoundation/edr-linux-arm64-musl@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.4.0.tgz#b1ce293a7c3e0d9f70391e1aef1a82b83b997567" - integrity sha512-D4J935ZRL8xfnP3zIFlCI9jXInJ0loDUkCTLeCEbOf2uuDumWDghKNQlF1itUS+EHaR1pFVBbuwqq8hVK0dASg== +"@nomicfoundation/edr-linux-arm64-musl@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.5.2.tgz#6676a09eab57c435a16ffc144658c896acca9baa" + integrity sha512-CwsQ10xFx/QAD5y3/g5alm9+jFVuhc7uYMhrZAu9UVF+KtVjeCvafj0PaVsZ8qyijjqVuVsJ8hD1x5ob7SMcGg== -"@nomicfoundation/edr-linux-x64-gnu@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.4.0.tgz#4c12c4e4bfd3d837f5663ad7cbf7cb6d5634ef83" - integrity sha512-6x7HPy+uN5Cb9N77e2XMmT6+QSJ+7mRbHnhkGJ8jm4cZvWuj2Io7npOaeHQ3YHK+TiQpTnlbkjoOIpEwpY3XZA== +"@nomicfoundation/edr-linux-x64-gnu@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.5.2.tgz#f558d9697ce961410e7a7468f9ab8c8a601b9df6" + integrity sha512-CWVCEdhWJ3fmUpzWHCRnC0/VLBDbqtqTGTR6yyY1Ep3S3BOrHEAvt7h5gx85r2vLcztisu2vlDq51auie4IU1A== -"@nomicfoundation/edr-linux-x64-musl@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.4.0.tgz#8842004aa1a47c504f10863687da28b65dca7baa" - integrity sha512-3HFIJSXgyubOiaN4MWGXx2xhTnhwlJk0PiSYNf9+L/fjBtcRkb2nM910ZJHTvqCb6OT98cUnaKuAYdXIW2amgw== +"@nomicfoundation/edr-linux-x64-musl@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.5.2.tgz#c9c9cbb2997499f75c1d022be724b0551d44569f" + integrity sha512-+aJDfwhkddy2pP5u1ISg3IZVAm0dO836tRlDTFWtvvSMQ5hRGqPcWwlsbobhDQsIxhPJyT7phL0orCg5W3WMeA== -"@nomicfoundation/edr-win32-x64-msvc@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.4.0.tgz#29d8bbb2edf9912a95f5453855cf17cdcb269957" - integrity sha512-CP4GsllEfXEz+lidcGYxKe5rDJ60TM5/blB5z/04ELVvw6/CK9eLcYeku7HV0jvV7VE6dADYKSdQyUkvd0El+A== +"@nomicfoundation/edr-win32-x64-msvc@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.5.2.tgz#f16db88bf4fe09a996af0a25096e09deecb72bfa" + integrity sha512-CcvvuA3sAv7liFNPsIR/68YlH6rrybKzYttLlMr80d4GKJjwJ5OKb3YgE6FdZZnOfP19HEHhsLcE0DPLtY3r0w== -"@nomicfoundation/edr@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.4.0.tgz#4895ecb6ef321136db837458949c37cce4a29459" - integrity sha512-T96DMSogO8TCdbKKctvxfsDljbhFOUKWc9fHJhSeUh71EEho2qR4951LKQF7t7UWEzguVYh/idQr5L/E3QeaMw== +"@nomicfoundation/edr@^0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.5.2.tgz#e8c7b3d3dd4a312432ab3930dec60f76dc5c4926" + integrity sha512-hW/iLvUQZNTVjFyX/I40rtKvvDOqUEyIi96T28YaLfmPL+3LW2lxmYLUXEJ6MI14HzqxDqrLyhf6IbjAa2r3Dw== dependencies: - "@nomicfoundation/edr-darwin-arm64" "0.4.0" - "@nomicfoundation/edr-darwin-x64" "0.4.0" - "@nomicfoundation/edr-linux-arm64-gnu" "0.4.0" - "@nomicfoundation/edr-linux-arm64-musl" "0.4.0" - "@nomicfoundation/edr-linux-x64-gnu" "0.4.0" - "@nomicfoundation/edr-linux-x64-musl" "0.4.0" - "@nomicfoundation/edr-win32-x64-msvc" "0.4.0" + "@nomicfoundation/edr-darwin-arm64" "0.5.2" + "@nomicfoundation/edr-darwin-x64" "0.5.2" + "@nomicfoundation/edr-linux-arm64-gnu" "0.5.2" + "@nomicfoundation/edr-linux-arm64-musl" "0.5.2" + "@nomicfoundation/edr-linux-x64-gnu" "0.5.2" + "@nomicfoundation/edr-linux-x64-musl" "0.5.2" + "@nomicfoundation/edr-win32-x64-msvc" "0.5.2" "@nomicfoundation/ethereumjs-common@4.0.4": version "4.0.4" @@ -1505,6 +1505,11 @@ "@pnpm/network.ca-file" "^1.0.1" config-chain "^1.1.11" +"@quant-finance/solidity-datetime@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@quant-finance/solidity-datetime/-/solidity-datetime-2.2.0.tgz#50f2d00a571d8cc2d962257b40b70fc44450dcaa" + integrity sha512-iO0EnqPKTzGCgQOkI9lerpJc0XKUhMNurSjHcA7p7nlP2K2z3U4kk9OC9eQkZUrdBtltft+kIibiDdIOYWuQMg== + "@resolver-engine/core@^0.3.3": version "0.3.3" resolved "https://registry.yarnpkg.com/@resolver-engine/core/-/core-0.3.3.tgz#590f77d85d45bc7ecc4e06c654f41345db6ca967" @@ -1693,6 +1698,34 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@skalenetwork/ima-interfaces@2.0.0-develop.67": + version "2.0.0-develop.67" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-2.0.0-develop.67.tgz#49b01c33cf04bc86c98a0425c742a0d993b9901f" + integrity sha512-PxzeXmIWuusESISG1lkeZVFXFpAL4szS673uFZPmFhcGXKrTf8ItG4n1eVFzUx4/egJkztRMk5Q9TJ9Unnv5vg== + dependencies: + "@skalenetwork/skale-manager-interfaces" "^3.2.0-develop.0" + +"@skalenetwork/ima-interfaces@^2.0.0-paymaster.0": + version "2.0.0-paymaster.0" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-2.0.0-paymaster.0.tgz#77663aec147ba430dc292aaf5b446eff21ed5fd4" + integrity sha512-B9PMcWcd+KkF0fudoQEAuTB2FohtOL/0l+GNlt4HvNvz/dOpsbVkCySrCQ/dCljV0/FSj45eJBgkTNCXyxYrbg== + dependencies: + "@skalenetwork/skale-manager-interfaces" "^3.2.0-paymaster.0" + +"@skalenetwork/marionette-interfaces@^0.0.0-main.6": + version "0.0.0-main.6" + resolved "https://registry.yarnpkg.com/@skalenetwork/marionette-interfaces/-/marionette-interfaces-0.0.0-main.6.tgz#51dcb8a9efbb4070606c4b4197d1317bbf404cd5" + integrity sha512-j+njN/HWTpcgDil8CP9rjMrL5e2l53astPevC3N5izJsJ63HNnP4phcPNQ9/nrNRfzff/3vsjVOns1xABX8Nvw== + dependencies: + "@skalenetwork/ima-interfaces" "^2.0.0-paymaster.0" + +"@skalenetwork/paymaster-interfaces@^1.0.0-main.10": + version "1.0.0-main.10" + resolved "https://registry.yarnpkg.com/@skalenetwork/paymaster-interfaces/-/paymaster-interfaces-1.0.0-main.10.tgz#abe2394bd948c3fac808e8cf09d91b99a59ac94d" + integrity sha512-P7Vc5F+hxeBrTDft2Th7jYY1N3lyzxsVMHkGhJd8Xjc3eSs4tLwvOE15vJPVBwwvqgnsdQwtsfNs+vF49o89LA== + dependencies: + "@quant-finance/solidity-datetime" "^2.2.0" + "@skalenetwork/skale-contracts-ethers-v6@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@skalenetwork/skale-contracts-ethers-v6/-/skale-contracts-ethers-v6-1.0.0.tgz#2ec9e1e6113c0b0e0e7abaa492702baa9d647148" @@ -1708,10 +1741,20 @@ dependencies: axios "^1.4.0" -"@skalenetwork/skale-manager-interfaces@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@skalenetwork/skale-manager-interfaces/-/skale-manager-interfaces-3.1.0.tgz#e97750462b1dafa9eee1c347802d5405afc9474f" - integrity sha512-lVJM6nRfIrlwRy7N009jGCZa5nDJo2/QMrKN0A2nRz/sqT8wWlOQUeDKrJ1mC5Esdbzhya6T6hTiZbN2yNwcRg== +"@skalenetwork/skale-manager-interfaces@3.2.0-develop.0": + version "3.2.0-develop.0" + resolved "https://registry.yarnpkg.com/@skalenetwork/skale-manager-interfaces/-/skale-manager-interfaces-3.2.0-develop.0.tgz#01e64eeabf2b14b320074eb588b557bbd33bab39" + integrity sha512-f++aLtSwjLJgAb3dHAm/SMHvx2a0L3uWwF7aam1wCtB6YZrFLR3flzlH3Ms3JlLZtfl5iE7VBmsuidhAqpbfpw== + +"@skalenetwork/skale-manager-interfaces@^3.2.0-develop.0": + version "3.2.0-paymaster.2" + resolved "https://registry.yarnpkg.com/@skalenetwork/skale-manager-interfaces/-/skale-manager-interfaces-3.2.0-paymaster.2.tgz#6b114041b623a030331e0a7853a2eab136fc2daf" + integrity sha512-tmqWNkafjJxIZNVp2EmysvXor5F4G+f5A4qTMWqCZ7yMrCAvGzTETpMiHGjJJCUwSIaaqd62DjDjQi69r+BUkg== + +"@skalenetwork/skale-manager-interfaces@^3.2.0-paymaster.0": + version "3.2.0-paymaster.0" + resolved "https://registry.yarnpkg.com/@skalenetwork/skale-manager-interfaces/-/skale-manager-interfaces-3.2.0-paymaster.0.tgz#4fee7d3a6dfd1dc8c446f6d28a2252fce426b537" + integrity sha512-AC0g3dMAtHORQnxm9QoZIgpNqTNwe/ahK9kPyTQFV/Ht3/sIoWkx0vXUiAwsDzK56HAVFXfc+LqfmEnKiefDqg== "@skalenetwork/upgrade-tools@^3.0.0-linter.42": version "3.0.0-linter.42" @@ -4004,6 +4047,11 @@ commander@^11.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== +commander@^8.1.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + comment-json@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-4.2.3.tgz#50b487ebbf43abe44431f575ebda07d30d015365" @@ -6661,14 +6709,14 @@ hardhat-dependency-compiler@^1.2.1: resolved "https://registry.yarnpkg.com/hardhat-dependency-compiler/-/hardhat-dependency-compiler-1.2.1.tgz#31a00e388029591b648f49ade74f56bfab11243b" integrity sha512-xG5iwbspTtxOEiP5UsPngEYQ1Hg+fjTjliapIjdTQmwGkCPofrsDhQDV2O/dopcYzcR68nTx2X8xTewYHgA2rQ== -hardhat@^2.22.5: - version "2.22.5" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.5.tgz#7e1a4311fa9e34a1cfe337784eae06706f6469a5" - integrity sha512-9Zq+HonbXCSy6/a13GY1cgHglQRfh4qkzmj1tpPlhxJDwNVnhxlReV6K7hCWFKlOrV13EQwsdcD0rjcaQKWRZw== +hardhat@^2.22.8: + version "2.22.8" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.8.tgz#348dcdb48c44648ae7723f6efb511785e2b220c5" + integrity sha512-hPh2feBGRswkXkoXUFW6NbxgiYtEzp/3uvVFjYROy6fA9LH8BobUyxStlyhSKj4+v1Y23ZoUBOVWL84IcLACrA== dependencies: "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/edr" "^0.4.0" + "@nomicfoundation/edr" "^0.5.2" "@nomicfoundation/ethereumjs-common" "4.0.4" "@nomicfoundation/ethereumjs-tx" "5.0.4" "@nomicfoundation/ethereumjs-util" "9.0.4" @@ -6702,7 +6750,7 @@ hardhat@^2.22.5: raw-body "^2.4.1" resolve "1.17.0" semver "^6.3.0" - solc "0.7.3" + solc "0.8.26" source-map-support "^0.5.13" stacktrace-parser "^0.1.10" tsort "0.0.1" @@ -10406,18 +10454,16 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -solc@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" - integrity sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA== +solc@0.8.26: + version "0.8.26" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.26.tgz#afc78078953f6ab3e727c338a2fefcd80dd5b01a" + integrity sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g== dependencies: command-exists "^1.2.8" - commander "3.0.2" + commander "^8.1.0" follow-redirects "^1.12.1" - fs-extra "^0.30.0" js-sha3 "0.8.0" memorystream "^0.3.1" - require-from-string "^2.0.0" semver "^5.5.0" tmp "0.0.33" @@ -10446,10 +10492,10 @@ solc@^0.6.3, solc@^0.6.7: semver "^5.5.0" tmp "0.0.33" -solhint@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/solhint/-/solhint-5.0.1.tgz#f0f783bd9d945e5a27b102295a3f28edba241d6c" - integrity sha512-QeQLS9HGCnIiibt+xiOa/+MuP7BWz9N7C5+Mj9pLHshdkNhuo3AzCpWmjfWVZBUuwIUO3YyCRVIcYLR3YOKGfg== +solhint@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-5.0.3.tgz#b57f6d2534fe09a60f9db1b92e834363edd1cbde" + integrity sha512-OLCH6qm/mZTCpplTXzXTJGId1zrtNuDYP5c2e6snIv/hdRVxPfBBz/bAlL91bY/Accavkayp2Zp2BaDSrLVXTQ== dependencies: "@solidity-parser/parser" "^0.18.0" ajv "^6.12.6"