Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- RandomNoManager
- Optimization enabled
- true
- Compiler version
- v0.8.4+commit.c7e474f2
- Optimization runs
- 3000
- Verified at
- 2022-08-26T14:36:06.720212Z
contracts/randomNumber/RandomNoManager.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../Core/parameters/child/RandomNoManagerParams.sol"; import "../Core/parameters/ACL.sol"; import "./IRandomNoClient.sol"; import "./IRandomNoProvider.sol"; import "../Initializable.sol"; import "../lib/Random.sol"; import "../Core/StateManager.sol"; import "./RandomNoStorage.sol"; /** * @title : RandomNoManager * @notice : Allows clients to register for random no, and pull it once available */ contract RandomNoManager is Initializable, StateManager, RandomNoStorage, RandomNoManagerParams, IRandomNoClient, IRandomNoProvider { event RandomNumberAvailable(uint32 epoch); /** * @param blockManagerAddress The address of the BlockManager Contract */ function initialize(address blockManagerAddress) external initializer onlyRole(DEFAULT_ADMIN_ROLE) { grantRole(SECRETS_MODIFIER_ROLE, blockManagerAddress); } /// @inheritdoc IRandomNoClient function register() external override initialized returns (bytes32 requestId) { uint32 epoch = _getEpoch(); nonce[msg.sender] = nonce[msg.sender] + 1; requestId = keccak256(abi.encodePacked(nonce[msg.sender], msg.sender)); requests[requestId] = epoch + 1; } /// @inheritdoc IRandomNoProvider function provideSecret(uint32 epoch, bytes32 _secret) external override initialized onlyRole(SECRETS_MODIFIER_ROLE) { /// @dev this require is added for extra assurance to clients, /// to give them assurance that once secret is set for epoch, it cant be changed /// as admin could always override this SECRETS_MODIFIER_ROLE role require(secrets[epoch] == 0x0, "Secret already set"); secrets[epoch] = _secret; emit RandomNumberAvailable(epoch); } /// @inheritdoc IRandomNoClient function getRandomNumber(bytes32 requestId) external view override returns (uint256) { uint32 epochOfRequest = requests[requestId]; return _generateRandomNumber(epochOfRequest, requestId); } /// @inheritdoc IRandomNoClient function getGenericRandomNumberOfLastEpoch() external view override returns (uint256) { uint32 epoch = _getEpoch(); return _generateRandomNumber(epoch - 1, 0); } /// @inheritdoc IRandomNoClient function getGenericRandomNumber(uint32 epoch) external view override returns (uint256) { return _generateRandomNumber(epoch, 0); } function _generateRandomNumber(uint32 epoch, bytes32 requestId) internal view returns (uint256) { bytes32 secret = secrets[epoch]; if (secret == 0x0) { revert("Random Number not genarated yet"); } else { return uint256(Random.prngHash(secret, requestId)); } } }
@openzeppelin/contracts/utils/Strings.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
contracts/Core/parameters/interfaces/ICollectionManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface ICollectionManagerParams { /** * @notice changing the maximum percentage deviation allowed from medians for all collections * @dev can be called only by the the address that has the governance role * @param _maxTolerance updated value for maxTolerance */ function setMaxTolerance(uint32 _maxTolerance) external; /** * @notice changing buffer length between the states * @dev can be called only by the the address that has the governance role * @param _bufferLength updated value to be set for buffer */ function setBufferLength(uint8 _bufferLength) external; }
@openzeppelin/contracts/access/AccessControl.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
contracts/tokenization/IStakedTokenFactory.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IStakedTokenFactory { /** * @dev a factory contract where the sRZR for a new staker is being deployed * @param stakeManagerAddress address of the stake Manager contract * @param stakedID id of the staker whom the sRZR is being deployed */ function createStakedToken(address stakeManagerAddress, uint32 stakedID) external returns (address); }
contracts/tokenization/StakedTokenFactory.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "./StakedToken.sol"; import "./IStakedTokenFactory.sol"; contract StakedTokenFactory is IStakedTokenFactory { /// @inheritdoc IStakedTokenFactory function createStakedToken(address stakeManagerAddress, uint32 stakerID) external override returns (address) { require(stakeManagerAddress != address(0x0), "zero address check"); StakedToken sToken = new StakedToken(stakeManagerAddress, stakerID); return address(sToken); } }
contracts/Core/parameters/child/CollectionManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../interfaces/ICollectionManagerParams.sol"; import "../ACL.sol"; import "../../storage/Constants.sol"; abstract contract CollectionManagerParams is ACL, ICollectionManagerParams, Constants { uint8 public buffer = 5; /// @notice maximum percentage deviation allowed from medians for all collections uint32 public maxTolerance = 1_000_000; /// @inheritdoc ICollectionManagerParams function setMaxTolerance(uint32 _maxTolerance) external override onlyRole(GOVERNANCE_ROLE) { // slither-reason: Disabled across all params childs // as they are being called by governance contract only // and their before setting, we are emitting event // slither-disable-next-line events-maths maxTolerance = _maxTolerance; } function setBufferLength(uint8 _bufferLength) external override onlyRole(GOVERNANCE_ROLE) { // slither-reason: Disabled across all params childs // as they are being called by governance contract only // and their before setting, we are emitting event // slither-disable-next-line events-maths buffer = _bufferLength; } }
contracts/Core/parameters/interfaces/IRewardManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IRewardManagerParams { /** * @notice changing the percentage stake penalty to be given out for inactivity * @dev can be called only by the the address that has the governance role * @param _penaltyNotRevealNumerator updated value to be set for penaltyNotRevealNumerator */ function setPenaltyNotRevealNum(uint32 _penaltyNotRevealNumerator) external; /** * @notice changing the percentage age penalty to be given out for inactivity * @dev can be called only by the the address that has the governance role * @param _penaltyAgeNotRevealNumerator updated value to be set for penaltyAgeNotRevealNumerator */ function setPenaltyAgeNotRevealNum(uint32 _penaltyAgeNotRevealNumerator) external; /** * @notice changing the block reward given out to stakers * @dev can be called only by the the address that has the governance role * @param _blockReward updated value to be set for blockReward */ function setBlockReward(uint256 _blockReward) external; /** * @notice changing the maximum age a staker can have * @dev can be called only by the the address that has the governance role * @param _maxAge updated value to be set for maxAge */ function setMaxAge(uint32 _maxAge) external; /** * @notice changing the maximum percentage deviation allowed from medians for all collections * @dev can be called only by the the address that has the governance role * @param _maxTolerance updated value for maxTolerance */ function setMaxTolerance(uint32 _maxTolerance) external; /** * @notice changing maximum commission stakers can charge from delegators on their profits * @dev can be called only by the the address that has the governance role * @param _maxCommission updated value to be set for maxCommission */ function setMaxCommission(uint8 _maxCommission) external; }
@openzeppelin/contracts/utils/cryptography/ECDSA.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
contracts/Core/storage/CollectionStorage.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../../lib/Structs.sol"; contract CollectionStorage { enum JobSelectorType { JSON, XHTML } /// @notice mapping for JobID -> Job Info mapping(uint16 => Structs.Job) public jobs; /// @notice mapping for CollectionID -> Collection Info mapping(uint16 => Structs.Collection) public collections; // For next epoch : Penalties /// @notice delayed mappping collectionid -> leafId mapping(uint16 => uint16) public collectionIdToLeafIdRegistryOfLastEpoch; /// For this epoch : Disputes /// @notice mapping for collectionid -> leafId mapping(uint16 => uint16) public collectionIdToLeafIdRegistry; /// @notice mapping for leafId -> collectionid mapping(uint16 => uint16) public leafIdToCollectionIdRegistry; /// @notice mapping for name of collection in bytes32 -> collectionid mapping(bytes32 => uint16) public ids; /// @notice number of active collections in the network uint16 public numActiveCollections; /// @notice epoch in which the registry needs to be updated uint32 public updateRegistryEpoch; /// @notice number of collections in the network uint16 public numCollections; /// @notice number of jobs in the network uint16 public numJobs; }
contracts/Core/interface/ICollectionManager.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface ICollectionManager { /** * @notice updates the collectionIdToLeafIdRegistryOfLastEpoch resgistries. * @dev It is called by the blockManager when a block is confirmed. It is only called if there was a change in the * status of collections in the network */ function updateDelayedRegistry() external; /** * @param id the id of the collection * @return status of the collection */ function getCollectionStatus(uint16 id) external view returns (bool); /** * @return total number of active collections */ function getNumActiveCollections() external view returns (uint16); /** * @return ids of active collections */ function getActiveCollections() external view returns (uint16[] memory); /** * @param id the id of the collection * @return power of the collection */ function getCollectionPower(uint16 id) external view returns (int8); /** * @return total number of collections */ function getNumCollections() external view returns (uint16); /** * @param i the leafId of the collection * @return tolerance of the collection */ function getCollectionTolerance(uint16 i) external view returns (uint32); /** * @param id the id of the collection * @return the leafId of the collection from collectionIdToLeafIdRegistry */ function getLeafIdOfCollection(uint16 id) external view returns (uint16); /** * @param leafId, the leafId of the collection * @return the id of the collection */ function getCollectionIdFromLeafId(uint16 leafId) external view returns (uint16); /** * @param id the id of the collection * @return the leafId of the collection from collectionIdToLeafIdRegistryOfLastEpoch */ function getLeafIdOfCollectionForLastEpoch(uint16 id) external view returns (uint16); /** * @param _name the name of the collection in bytes32 * @return collection ID */ function getCollectionID(bytes32 _name) external view returns (uint16); /** * @notice returns the result of the collection based on the name sent by the client * @param _name the name of the collection in bytes32 * @return result of the collection * @return power of the resultant collection */ function getResult(bytes32 _name) external view returns (uint256, int8); /** * @notice returns the result of the collection based on the id sent by the client * @param _id the id of the collection * @return result of the collection * @return power of the resultant collection */ function getResultFromID(uint16 _id) external view returns (uint256, int8); /** * @return epoch in which the registry needs to be updated */ function getUpdateRegistryEpoch() external view returns (uint32); }
contracts/mocks/MerklePosAwareTest.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../lib/MerklePosAware.sol"; contract MerklePosAwareTest { function verifyMultiple( bytes32[][] memory proofs, bytes32 root, bytes32[] memory leaves, uint16[] memory leafId, uint256 depth, uint16 maxAssets ) external pure returns (bool) { return MerklePosAware.verifyMultiple(proofs, root, leaves, leafId, depth, maxAssets); } function getSequence(uint256 leafId, uint256 depth) external pure returns (bytes memory) { return MerklePosAware.getSequence(leafId, depth); } //function getSequence(uint256 leafId, uint256 depth) external // function verify( // bytes32[] memory proof, // bytes32 root, // bytes32 leaf, // uint16 leafId, // uint256 depth, // uint16 maxAssets // ) external pure returns (bool) { // return MerklePosAware.verify(proof, root, leaf, leafId, depth, maxAssets); // } // function getSequence(uint256 leafId, uint256 depth) external pure returns (string memory) { // return string(MerklePosAware.getSequence(leafId, depth)); // } }
contracts/Core/RewardManager.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "./interface/IBlockManager.sol"; import "./interface/IStakeManager.sol"; import "./interface/IVoteManager.sol"; import "./interface/IRewardManager.sol"; import "./interface/ICollectionManager.sol"; import "../tokenization/IStakedToken.sol"; import "../Initializable.sol"; import "./storage/Constants.sol"; import "./parameters/child/RewardManagerParams.sol"; /** @title RewardManager * @notice RewardManager gives penalties and rewards to stakers based on * their behaviour */ contract RewardManager is Initializable, Constants, RewardManagerParams, IRewardManager { IStakeManager public stakeManager; IVoteManager public voteManager; IBlockManager public blockManager; ICollectionManager public collectionManager; /** * @param stakeManagerAddress The address of the StakeManager contract * @param voteManagersAddress The address of the VoteManager contract * @param blockManagerAddress The address of the BlockManager contract * @param collectionManagerAddress The address of the CollectionManager contract */ function initialize( address stakeManagerAddress, address voteManagersAddress, address blockManagerAddress, address collectionManagerAddress ) external initializer onlyRole(DEFAULT_ADMIN_ROLE) { stakeManager = IStakeManager(stakeManagerAddress); voteManager = IVoteManager(voteManagersAddress); blockManager = IBlockManager(blockManagerAddress); collectionManager = ICollectionManager(collectionManagerAddress); } /// @inheritdoc IRewardManager function givePenalties(uint32 epoch, uint32 stakerId) external override initialized onlyRole(REWARD_MODIFIER_ROLE) { _givePenalties(epoch, stakerId); } /// @inheritdoc IRewardManager function giveBlockReward(uint32 stakerId, uint32 epoch) external override initialized onlyRole(REWARD_MODIFIER_ROLE) { Structs.Staker memory staker = stakeManager.getStaker(stakerId); IStakedToken sToken = IStakedToken(staker.tokenAddress); uint256 totalSupply = sToken.totalSupply(); uint256 stakerSRZR = sToken.balanceOf(staker._address); uint256 delegatorShare = blockReward - ((blockReward * stakerSRZR) / totalSupply); uint8 commissionApplicable = staker.commission < maxCommission ? staker.commission : maxCommission; uint256 stakerReward = (delegatorShare * commissionApplicable) / 100; stakeManager.setStakerStake(epoch, stakerId, StakeChanged.BlockReward, staker.stake, staker.stake + (blockReward - stakerReward)); stakeManager.setStakerReward( epoch, stakerId, StakerRewardChanged.StakerRewardAdded, staker.stakerReward, staker.stakerReward + stakerReward ); } /// @inheritdoc IRewardManager function giveInactivityPenalties(uint32 epoch, uint32 stakerId) external override initialized onlyRole(REWARD_MODIFIER_ROLE) { _giveInactivityPenalties(epoch, stakerId); } /** * @dev inactivity penalties are given to stakers if they have been inactive for more than the grace period. * For each inactive epoch, stakers lose their age by 1*10000 and their stake by penaltyNotRevealNum. * Activity is calculated based on the epoch the staker last revealed in. */ function _giveInactivityPenalties(uint32 epoch, uint32 stakerId) internal { uint32 epochLastRevealed = voteManager.getEpochLastRevealed(stakerId); Structs.Staker memory thisStaker = stakeManager.getStaker(stakerId); uint32 epochLastActive = thisStaker.epochFirstStakedOrLastPenalized < epochLastRevealed ? epochLastRevealed : thisStaker.epochFirstStakedOrLastPenalized; // penalize or reward if last active more than epoch - 1 uint32 inactiveEpochs = (epoch - epochLastActive == 0) ? 0 : epoch - epochLastActive - 1; uint256 previousStake = thisStaker.stake; uint256 newStake = thisStaker.stake; uint32 previousAge = thisStaker.age; uint32 newAge = thisStaker.age; if (inactiveEpochs > 0) { (newStake, newAge) = _calculateInactivityPenalties(inactiveEpochs, newStake, previousAge); } // uint256 currentStake = previousStake; if (newStake < previousStake) { stakeManager.setStakerEpochFirstStakedOrLastPenalized(epoch, stakerId); stakeManager.setStakerStake(epoch, stakerId, StakeChanged.InactivityPenalty, previousStake, newStake); } if (newAge < previousAge) { stakeManager.setStakerAge(epoch, stakerId, newAge, AgeChanged.InactivityPenalty); } } /** * @dev Penalties are given to stakers based their activity if they have been inactive for more than the grace period * and their votes in the previous epoch compared to the medians confirmed. Penalties on votes depend upon how far were * the staker's votes from the median value. There is tolerance being added for each collection thereby not penalizing * stakers of their vote was within the tolerance limits of the collection */ function _givePenalties(uint32 epoch, uint32 stakerId) internal { _giveInactivityPenalties(epoch, stakerId); Structs.Staker memory thisStaker = stakeManager.getStaker(stakerId); uint32 epochLastRevealed = voteManager.getEpochLastRevealed(stakerId); if (epochLastRevealed != 0 && epochLastRevealed < epoch - 1) { return; } uint64 age = thisStaker.age + 10000; // cap age to maxAge age = age > maxAge ? maxAge : age; Structs.Block memory _block = blockManager.getBlock(epochLastRevealed); uint16[] memory idsRevealedLastEpoch = _block.ids; uint256[] memory mediansLastEpoch = _block.medians; if (idsRevealedLastEpoch.length == 0) return; uint256 penalty = 0; for (uint16 i = 0; i < idsRevealedLastEpoch.length; i++) { // get leaf id from collection id, as voting happens w.r.t leaf ids // slither-disable-next-line calls-loop uint16 leafId = collectionManager.getLeafIdOfCollectionForLastEpoch(idsRevealedLastEpoch[i]); // slither-disable-next-line calls-loop uint256 voteValueLastEpoch = voteManager.getVoteValue(epoch - 1, stakerId, leafId); if ( voteValueLastEpoch != 0 ) // Only penalise if given asset revealed, please note here again revealed value of asset cant be zero { uint256 medianLastEpoch = mediansLastEpoch[i]; if (medianLastEpoch == 0) continue; //WARNING: unreachable. Can be removed uint256 prod = age * voteValueLastEpoch; // slither-disable-next-line calls-loop uint32 tolerance = collectionManager.getCollectionTolerance(idsRevealedLastEpoch[i]); tolerance = tolerance <= maxTolerance ? tolerance : maxTolerance; uint256 maxVoteTolerance = medianLastEpoch + ((medianLastEpoch * tolerance) / BASE_DENOMINATOR); uint256 minVoteTolerance = medianLastEpoch - ((medianLastEpoch * tolerance) / BASE_DENOMINATOR); // if (voteWeightLastEpoch > 0) { if (voteValueLastEpoch > maxVoteTolerance) { //penalty = age(vote/maxvote-1) penalty = penalty + (prod / maxVoteTolerance - age); } else if (voteValueLastEpoch < minVoteTolerance) { //penalty = age(1-vote/minvote) penalty = penalty + (age - prod / minVoteTolerance); } } } age = penalty > age ? 0 : age - uint32(penalty); stakeManager.setStakerAge(epoch, thisStaker.id, uint32(age), AgeChanged.VotingRewardOrPenalty); } /** @notice Calculates the stake and age inactivity penalties of the staker * @param epochs The difference of epochs where the staker was inactive * @param stakeValue The Stake that staker had in last epoch * @param ageValue The age that staker had in last epoch */ function _calculateInactivityPenalties( uint32 epochs, uint256 stakeValue, uint32 ageValue ) internal view returns (uint256, uint32) { uint256 penalty = ((epochs) * (stakeValue * penaltyNotRevealNum)) / BASE_DENOMINATOR; uint256 newStake = penalty < stakeValue ? stakeValue - penalty : 0; uint256 penaltyAge = (uint256(epochs) * (uint256(ageValue) * uint256(penaltyAgeNotRevealNum))) / BASE_DENOMINATOR; uint32 newAge = uint32(penaltyAge) < ageValue ? ageValue - uint32(penaltyAge) : 0; return (newStake, newAge); } }
contracts/tokenization/RAZOR.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; /** * @title RAZOR * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator. * Note they can later distribute these tokens as they wish using `transfer` and other * `ERC20` functions. */ contract RAZOR is ERC20 { /** * @dev Constructor that gives msg.sender all of existing tokens. */ constructor(uint256 initialSupply) ERC20("RAZOR", "RAZOR") { _mint(msg.sender, initialSupply); } }
@openzeppelin/contracts/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
contracts/IDelegator.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IDelegator { /** * @dev updates the address of the Collection Manager contract from where the delegator will fetch * results of the oracle * @param newDelegateAddress address of the Collection Manager * @param newRandomNoManagerAddress address of the Random Number Manager */ function updateAddress(address newDelegateAddress, address newRandomNoManagerAddress) external; /** * @notice Allows Client to register for random number * Per request a rquest id is generated, which is binded to one epoch * this epoch is current epoch if Protocol is in commit state, or epoch + 1 if in any other state * @return requestId : unique request id */ function register() external returns (bytes32); /** * @dev using the hash of collection name, clients can query collection id with respect to its hash * @param _name bytes32 hash of the collection name * @return collection ID */ function getCollectionID(bytes32 _name) external view returns (uint16); /** * @dev using the hash of collection name, clients can query the result of that collection * @param _name bytes32 hash of the collection name * @return result of the collection and its power */ function getResult(bytes32 _name) external view returns (uint256, int8); /** * @dev using the collection id, clients can query the result of the collection * @param _id collection ID * @return result of the collection and its power */ function getResultFromID(uint16 _id) external view returns (uint256, int8); /** * @return ids of active collections in the oracle */ function getActiveCollections() external view returns (uint16[] memory); /** * @dev using the collection id, clients can query the status of collection * @param _id collection ID * @return status of the collection */ function getCollectionStatus(uint16 _id) external view returns (bool); /** * @notice Allows client to pull random number once available * Random no is generated from secret of that epoch and request id, its unique per requestid * @param requestId : A unique id per request */ function getRandomNumber(bytes32 requestId) external view returns (uint256); /** * @notice Fetch generic random number of last epoch * @return random number */ function getGenericRandomNumberOfLastEpoch() external view returns (uint256); /** * @dev using epoch, clients can query random number generated of the epoch * @param _epoch epoch * @return random number */ function getGenericRandomNumber(uint32 _epoch) external view returns (uint256); }
contracts/Core/parameters/child/BlockManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../interfaces/IBlockManagerParams.sol"; import "../ACL.sol"; import "../../storage/Constants.sol"; abstract contract BlockManagerParams is ACL, IBlockManagerParams, Constants { /// @notice maximum number of best proposed blocks to be considered for dispute uint8 public maxAltBlocks = 5; uint8 public buffer = 5; /// @notice reward given to staker whose block is confirmed uint256 public blockReward = 100 * (10**18); /// @notice minimum amount of stake required to participate uint256 public minStake = 20000 * (10**18); /// @inheritdoc IBlockManagerParams function setMaxAltBlocks(uint8 _maxAltBlocks) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths maxAltBlocks = _maxAltBlocks; } function setBufferLength(uint8 _bufferLength) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths buffer = _bufferLength; } /// @inheritdoc IBlockManagerParams function setBlockReward(uint256 _blockReward) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths blockReward = _blockReward; } /// @inheritdoc IBlockManagerParams function setMinStake(uint256 _minStake) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths minStake = _minStake; } }
contracts/tokenization/IStakedToken.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IStakedToken is IERC20 { /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function mint( address account, uint256 amount, uint256 razorDeposited ) external returns (bool); /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function burn(address account, uint256 amount) external returns (bool); /// @notice Used in withdraw // At any time via calling this one can find out how much RZR was deposited for this much sRZR function getRZRDeposited(address delegator, uint256 sAmount) external view returns (uint256); }
contracts/Core/parameters/interfaces/IVoteManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IVoteManagerParams { /** * @notice changing minimum amount that to be staked for participation * @dev can be called only by the the address that has the governance role * @param _minStake updated value to be set for minStake */ function setMinStake(uint256 _minStake) external; /** * @notice changing maximum number of collections that can be assigned to the staker * @dev can be called only by the the address that has the governance role * @param _toAssign updated value to be set for toAssign */ function setToAssign(uint16 _toAssign) external; /** * @notice changing buffer length between the states * @dev can be called only by the the address that has the governance role * @param _bufferLength updated value to be set for buffer */ function setBufferLength(uint8 _bufferLength) external; }
contracts/Core/parameters/ACL.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/AccessControl.sol"; contract ACL is AccessControl { /** * @dev the deployer of the network is given to the default admin role which gives other roles to contracts */ constructor() { _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); } }
contracts/randomNumber/IRandomNoClient.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IRandomNoClient { /** * @notice Allows Client to register for random number * Per request a rquest id is generated, which is binded to one epoch * this epoch is current epoch if Protocol is in commit state, or epoch + 1 if in any other state * @return requestId : unique request id */ function register() external returns (bytes32); /** * @notice Allows client to pull random number once available * Random no is generated from secret of that epoch and request id, its unique per requestid * @param requestId : A unique id per request */ function getRandomNumber(bytes32 requestId) external view returns (uint256); /** * @notice Allows client to get generic random number of last epoch * @return random number */ function getGenericRandomNumberOfLastEpoch() external view returns (uint256); /** * @notice Allows client to get generic random number of any epoch * @param epoch random no of which epoch * @return random number */ function getGenericRandomNumber(uint32 epoch) external view returns (uint256); }
contracts/Core/CollectionManager.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "./interface/ICollectionManager.sol"; import "./interface/IBlockManager.sol"; import "./interface/IVoteManager.sol"; import "./storage/CollectionStorage.sol"; import "../Initializable.sol"; import "./parameters/child/CollectionManagerParams.sol"; import "./StateManager.sol"; contract CollectionManager is Initializable, CollectionStorage, StateManager, CollectionManagerParams, ICollectionManager { IBlockManager public blockManager; IVoteManager public voteManager; /** * @dev Emitted when a job has been created * @param id the id of the job that was created * @param timestamp time at which the job was created */ event JobCreated(uint16 indexed id, uint256 timestamp); /** * @dev Emitted when a collection has been created * @param id the id of the collection that was created * @param timestamp time at which the collection was created */ event CollectionCreated(uint16 indexed id, uint256 timestamp); /** * @dev Emitted when a job has been updated * @param id the id of the job that was updated * @param selectorType updated selector type of the job * @param epoch in which the job was updated * @param weight updated weight * @param power updated power * @param timestamp time at which the job was updated * @param selector updated selector * @param url updated url */ event JobUpdated( uint16 indexed id, JobSelectorType selectorType, uint32 epoch, uint8 weight, int8 power, uint256 timestamp, string selector, string url ); /** * @dev Emiited when there is a change in status of an existing collection * @param active updated status of the collection * @param id of the collection for which the status has been changed * @param epoch in which the status change took place * @param timestamp time at which the status change took place */ event CollectionActivityStatus(bool active, uint16 indexed id, uint32 epoch, uint256 timestamp); /** * @dev Emitted when a collection has been updated * @param id the id of the collection that was updated * @param power updated power * @param epoch in which the collection was updated * @param aggregationMethod updated aggregationMethod * @param tolerance updated tolerance * @param updatedJobIDs updated job ids for the collections * @param timestamp time at which the collection was updated */ event CollectionUpdated( uint16 indexed id, int8 power, uint32 epoch, uint32 aggregationMethod, uint32 tolerance, uint16[] updatedJobIDs, uint256 timestamp ); /** * @param voteManagerAddress The address of the Vote Manager contract * @param blockManagerAddress The address of the Block Manager contract */ function initialize(address voteManagerAddress, address blockManagerAddress) external initializer onlyRole(DEFAULT_ADMIN_ROLE) { voteManager = IVoteManager(voteManagerAddress); blockManager = IBlockManager(blockManagerAddress); } /** @notice Creates a Job in the network. * @dev Jobs are not directly reported by staker but just stores the URL and its corresponding details * @param weight specifies the weight the result of each job carries * @param power is used to specify the decimal shifts required on the result of a Job query * @param selectorType defines the selectorType of the URL. Can be JSON/XHTML * @param name of the URL * @param selector of the URL * @param url to be used for retrieving the data */ function createJob( uint8 weight, int8 power, JobSelectorType selectorType, string calldata name, string calldata selector, string calldata url ) external initialized onlyRole(COLLECTION_MODIFIER_ROLE) { require(weight <= 100, "Weight beyond max"); numJobs = numJobs + 1; jobs[numJobs] = Structs.Job(numJobs, uint8(selectorType), weight, power, name, selector, url); emit JobCreated(numJobs, block.timestamp); } /** * @notice Updates a Job in the network. * @param jobID the job id for which the details need to change * @param weight specifies the weight the result of each job carries * @param power is used to specify the decimal shifts required on the result of a Job query * @param selectorType defines the selectorType of the URL. Can be JSON/XHTML * @param selector of the URL * @param url to be used for retrieving the data */ function updateJob( uint16 jobID, uint8 weight, int8 power, JobSelectorType selectorType, string calldata selector, string calldata url ) external initialized onlyRole(COLLECTION_MODIFIER_ROLE) notState(State.Commit, buffer) { require(jobID != 0, "ID cannot be 0"); require(jobs[jobID].id == jobID, "Job ID not present"); require(weight <= 100, "Weight beyond max"); uint32 epoch = _getEpoch(); jobs[jobID].url = url; jobs[jobID].selector = selector; jobs[jobID].selectorType = uint8(selectorType); jobs[jobID].weight = weight; jobs[jobID].power = power; emit JobUpdated(jobID, selectorType, epoch, weight, power, block.timestamp, selector, url); } /** @notice Sets the status of the collection in the network. * @param assetStatus the status that needs to be set for the collection * @param id the collection id for which the status needs to change */ function setCollectionStatus(bool assetStatus, uint16 id) external initialized onlyRole(COLLECTION_MODIFIER_ROLE) checkState(State.Confirm, buffer) { require(id != 0, "ID cannot be 0"); require(id <= numCollections, "ID does not exist"); uint32 epoch = _getEpoch(); // slither-disable-next-line incorrect-equality,timestamp if (updateRegistryEpoch <= epoch) { _updateDelayedRegistry(); } if (assetStatus) { require(!collections[id].active, "ID already active"); numActiveCollections = numActiveCollections + 1; collections[id].active = assetStatus; } else { require(collections[id].active, "ID already inactive"); numActiveCollections = numActiveCollections - 1; collections[id].active = assetStatus; } updateRegistryEpoch = epoch + 1; _updateRegistry(); emit CollectionActivityStatus(collections[id].active, id, epoch, block.timestamp); voteManager.storeDepth(_getDepth()); // update depth now only, as from next epoch's commit it starts } /** @notice Creates a collection in the network. * @dev Collections are to be reported by staker by querying the URLs in each job assigned in the collection * and aggregating them based on the aggregation method specified in the collection * @param tolerance specifies the percentage by which the staker's value can deviate from the value decided by the network * @param power is used to specify the decimal shifts required on the result of a Collection * @param aggregationMethod specifies the aggregation method to be used by the stakers * @param jobIDs an array that holds which jobs should the stakers query for the stakers to report for the collection * @param name of the collection */ function createCollection( uint32 tolerance, int8 power, uint32 aggregationMethod, uint16[] memory jobIDs, string calldata name ) external initialized onlyRole(COLLECTION_MODIFIER_ROLE) checkState(State.Confirm, buffer) { require(jobIDs.length > 0, "no jobs added"); require(tolerance <= maxTolerance, "Invalid tolerance value"); uint32 epoch = _getEpoch(); // slither-disable-next-line incorrect-equality,timestamp if (updateRegistryEpoch <= epoch) { _updateDelayedRegistry(); } uint256 jobsLength = jobIDs.length; for (uint8 i = 0; i < jobsLength; i++) { require(jobs[jobIDs[i]].id == jobIDs[i], "job not present"); } numCollections = numCollections + 1; collections[numCollections] = Structs.Collection(true, numCollections, power, tolerance, aggregationMethod, jobIDs, name); numActiveCollections = numActiveCollections + 1; updateRegistryEpoch = epoch + 1; _updateRegistry(); emit CollectionCreated(numCollections, block.timestamp); _setIDName(name, numCollections); voteManager.storeDepth(_getDepth()); } /** @notice Updates a Collection in the network. * @param collectionID the collection id for which the details need to change * @param tolerance specifies the percentage by which the staker's value can deviate from the value decided by the network * @param aggregationMethod specifies the aggregation method to be used by the stakers * @param power is used to specify the decimal shifts required on the result of a Collection * @param jobIDs an array that holds which jobs should the stakers query for the stakers to report for the collection */ function updateCollection( uint16 collectionID, uint32 tolerance, uint32 aggregationMethod, int8 power, uint16[] memory jobIDs ) external initialized onlyRole(COLLECTION_MODIFIER_ROLE) notState(State.Commit, buffer) { require(jobIDs.length > 0, "no jobs added"); require(collectionID <= numCollections, "Collection ID not present"); require(tolerance <= maxTolerance, "Invalid tolerance value"); uint32 epoch = _getEpoch(); uint256 jobsLength = jobIDs.length; for (uint8 i = 0; i < jobsLength; i++) { require(jobs[jobIDs[i]].id == jobIDs[i], "job not present"); } collections[collectionID].power = power; collections[collectionID].tolerance = tolerance; collections[collectionID].aggregationMethod = aggregationMethod; collections[collectionID].jobIDs = jobIDs; emit CollectionUpdated(collectionID, power, epoch, aggregationMethod, tolerance, jobIDs, block.timestamp); } /// @inheritdoc ICollectionManager function updateDelayedRegistry() external override initialized onlyRole(REGISTRY_MODIFIER_ROLE) { _updateDelayedRegistry(); } /** * @param id the id of the job * @return job the Struct of the job information */ function getJob(uint16 id) external view returns (Structs.Job memory job) { require(id != 0, "ID cannot be 0"); require(id <= numJobs, "ID does not exist"); return jobs[id]; } /** * @param id the id of the collection * @return collection the Struct of the collection information */ function getCollection(uint16 id) external view returns (Structs.Collection memory collection) { require(id != 0, "ID cannot be 0"); require(id <= numCollections, "ID does not exist"); return collections[id]; } /// @inheritdoc ICollectionManager function getResult(bytes32 _name) external view override returns (uint256, int8) { uint16 id = ids[_name]; return getResultFromID(id); } /// @inheritdoc ICollectionManager function getCollectionStatus(uint16 id) external view override returns (bool) { return collections[id].active; } /// @inheritdoc ICollectionManager function getCollectionTolerance(uint16 id) external view override returns (uint32) { return collections[id].tolerance; } /// @inheritdoc ICollectionManager function getCollectionPower(uint16 id) external view override returns (int8) { require(id <= numCollections, "ID does not exist"); return collections[id].power; } /// @inheritdoc ICollectionManager function getCollectionID(bytes32 _hname) external view override returns (uint16) { return ids[_hname]; } /** * @return total number of jobs */ function getNumJobs() external view returns (uint16) { return numJobs; } /// @inheritdoc ICollectionManager function getNumCollections() external view override returns (uint16) { return numCollections; } /// @inheritdoc ICollectionManager function getNumActiveCollections() external view override returns (uint16) { return numActiveCollections; } /// @inheritdoc ICollectionManager function getUpdateRegistryEpoch() external view override returns (uint32) { return updateRegistryEpoch; } /// @inheritdoc ICollectionManager function getLeafIdOfCollection(uint16 id) external view override returns (uint16) { return collectionIdToLeafIdRegistry[id]; } /// @inheritdoc ICollectionManager function getLeafIdOfCollectionForLastEpoch(uint16 id) external view override returns (uint16) { return collectionIdToLeafIdRegistryOfLastEpoch[id]; } /// @inheritdoc ICollectionManager function getCollectionIdFromLeafId(uint16 leafId) external view override returns (uint16) { return leafIdToCollectionIdRegistry[leafId]; } /** * @return array of active collections */ function getActiveCollections() external view override returns (uint16[] memory) { uint16[] memory result = new uint16[](numActiveCollections); uint16 j = 0; for (uint16 i = 1; i <= numCollections; i++) { if (collections[i].active) { result[j] = i; j = j + 1; } } return result; } function getDepth() external view returns (uint256) { return _getDepth(); } /// @inheritdoc ICollectionManager function getResultFromID(uint16 _id) public view override returns (uint256, int8) { return (blockManager.getLatestResults(_id), collections[_id].power); } /** * @dev updates the collectionIdToLeafIdRegistry and leafIdToCollectionIdRegistry everytime a collection has been activated/deactivated/created * being called by setCollectionStatus and createCollection in CollectionManager */ function _updateRegistry() internal { uint16 j = 0; for (uint16 i = 1; i <= numCollections; i++) { if (collections[i].active) { collectionIdToLeafIdRegistry[i] = j; leafIdToCollectionIdRegistry[j] = i; j = j + 1; } else { collectionIdToLeafIdRegistry[i] = 0; } } } /** being called by claimBlockReward and confirmPreviousBlockEpoch in block manager by setCollectionStatus and createCollection in CollectionManager */ function _updateDelayedRegistry() internal { uint16 j = 0; for (uint16 i = 1; i <= numCollections; i++) { if (collections[i].active) { collectionIdToLeafIdRegistryOfLastEpoch[i] = j; j = j + 1; } else { collectionIdToLeafIdRegistryOfLastEpoch[i] = 0; } } } /** * @dev hashes the name of the collection and the hashed value is mapped to its corresponding collection ID */ function _setIDName(string calldata name, uint16 _id) internal { bytes32 _name = keccak256(abi.encodePacked(name)); require(ids[_name] == 0, "Collection exists with same name"); ids[_name] = _id; } /** * @dev calculates the current depth of the merkle tree that stakers have to submit at the time of commit/reveal */ function _getDepth() internal view returns (uint256 n) { // numActiveCollection is uint16, so further range not needed // Inspired and modified from : https://medium.com/coinmonks/math-in-solidity-part-5-exponent-and-logarithm-9aef8515136e // 100000; // >= 2**4 , n = 4 // 000010; // >= 2**1 // n = n+ 1 == 5 uint256 x = numActiveCollections; // X = 2 ** n ; // Optimised way // for (; x > 0; x >>= 1) { // if (x >= 2**8) { x >>= 8; n += 8; } // if (x >= 2**4) { x >>= 4; n += 4; } // if (x >= 2**2) { x >>= 2; n += 2; } // if (x >= 2**1) { x >>= 1; n += 1; } // if (x == 1) { x >>= 1; n += 1; } // } // for 6 // 110 // optimised version of above would return 2 // 000 // but we want 3 // so we have to give importance to 1(1)0 as well // as in our case result for 100 and 110 is diff // so thats why we have to go unoptimised way // I dont know if we can use above optimised way and somehow detect that in middle(1) as well // So thats why lets have above as commented // and check in new issue, if we could do so //6 //110, 6 //011, 3 //001, 1 //000, 0 // 8 // 1000 // 0100 // 0010 // 0001 // 0000 // Have tested function upto 2**16; bool flag = false; for (n = 0; x > 1; x >>= 1) { // O(n) 1<n<=16 if (x % 2 != 0) flag = true; // for that (1) n += 1; } if (flag) n++; } }
contracts/Core/interface/IBlockManager.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../../lib/Structs.sol"; interface IBlockManager { /** * @notice if the proposed staker, whose block is valid and has the lowest iteration, does not call claimBlockReward() * then in commit state, the staker who commits first will confirm this block and will receive the block reward inturn * @param stakerId id of the staker that is confirming the block */ function confirmPreviousEpochBlock(uint32 stakerId) external; /** * @notice return the struct of the confirmed block * @param epoch in which this block was confirmed * @return _block : struct of the confirmed block */ function getBlock(uint32 epoch) external view returns (Structs.Block memory _block); /** * @notice this is to check whether a block was confirmed in a particular epoch or not * @param epoch for which this check is being done * @return true or false. true if a block has been confirmed, else false */ function isBlockConfirmed(uint32 epoch) external view returns (bool); /** * @notice Allows to get latest result of collection from id, used by delegator * @param id Collection ID */ function getLatestResults(uint16 id) external view returns (uint256); }
contracts/Core/parameters/interfaces/IBlockManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IBlockManagerParams { /** * @notice changing the maximum number of best proposed blocks to be considered for dispute * @dev can be called only by the the address that has the governance role * @param _maxAltBlocks updated value to be set for maxAltBlocks */ function setMaxAltBlocks(uint8 _maxAltBlocks) external; /** * @notice changing the block reward given out to stakers * @dev can be called only by the the address that has the governance role * @param _blockReward updated value to be set for blockReward */ function setBlockReward(uint256 _blockReward) external; /** * @notice changing minimum amount that to be staked for participation * @dev can be called only by the the address that has the governance role * @param _minStake updated value to be set for minStake */ function setMinStake(uint256 _minStake) external; /** * @notice changing buffer length between the states * @dev can be called only by the the address that has the governance role * @param _bufferLength updated value to be set for buffer */ function setBufferLength(uint8 _bufferLength) external; }
contracts/Core/storage/BlockStorage.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../../lib/Structs.sol"; contract BlockStorage { /// @notice mapping of epoch -> address -> dispute mapping(uint32 => mapping(address => Structs.Dispute)) public disputes; /// @notice mapping of epoch -> blockId -> block mapping(uint32 => mapping(uint32 => Structs.Block)) public proposedBlocks; /// @notice mapping of epoch->blockId mapping(uint32 => uint32[]) public sortedProposedBlockIds; /// @notice mapping of stakerId->epoch mapping(uint32 => uint32) public epochLastProposed; // @notice mapping for latest results of collection id->result mapping(uint16 => uint256) public latestResults; /// @notice total number of proposed blocks in an epoch // slither-disable-next-line constable-states uint32 public numProposedBlocks; /// @notice block index that is to be confirmed if not disputed // slither-disable-next-line constable-states int8 public blockIndexToBeConfirmed; // Index in sortedProposedBlockIds /// @notice mapping of epoch -> blocks mapping(uint32 => Structs.Block) public blocks; }
contracts/lib/MerklePosAware.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle trees (hash trees), */ library MerklePosAware { function verifyMultiple( bytes32[][] memory proofs, bytes32 root, bytes32[] memory leaves, uint16[] memory leafId, uint256 depth, uint16 maxAssets ) internal pure returns (bool) { for (uint256 i = 0; i < proofs.length; i++) { if (!verify(proofs[i], root, leaves[i], leafId[i], depth, maxAssets)) return false; } return true; } /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify( bytes32[] memory proof, bytes32 root, bytes32 leaf, uint16 leafId, uint256 depth, uint16 maxAssets ) internal pure returns (bool) { bytes32 computedHash = leaf; bytes memory seq = bytes(getSequence(leafId, depth)); uint256 lastNode = maxAssets; uint256 myNode = leafId + 1; uint256 j = depth; uint256 i = 0; while (j > 0) { bytes32 proofElement = proof[i]; j--; //skip proof check if my node is last node and number of nodes on level is odd if (lastNode % 2 == 1 && lastNode == myNode) { myNode = myNode / 2 + (myNode % 2); // (myNode % 2) always equal to 1 lastNode = lastNode / 2 + (lastNode % 2); // (lastNode % 2) always equal to 1 continue; } // 0x30 is 0, 0x31 is 1 if (seq[j] == 0x30) { computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); } else { computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } i++; myNode = myNode / 2 + (myNode % 2); lastNode = lastNode / 2 + (lastNode % 2); } return computedHash == root; } function getSequence(uint256 leafId, uint256 depth) internal pure returns (bytes memory) { bytes memory output = new bytes(depth); for (uint8 i = 0; i < depth; i++) { output[depth - 1 - i] = (leafId % 2 == 1) ? bytes1("1") : bytes1("0"); leafId /= 2; } return output; } }
contracts/Core/parameters/child/RandomNoManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../interfaces/IRandomNoManagerParams.sol"; import "../ACL.sol"; import "../../storage/Constants.sol"; abstract contract RandomNoManagerParams is ACL, IRandomNoManagerParams, Constants { uint8 public buffer = 5; function setBufferLength(uint8 _bufferLength) external override onlyRole(GOVERNANCE_ROLE) { // slither-reason: Disabled across all params childs // as they are being called by governance contract only // and their before setting, we are emitting event // slither-disable-next-line events-maths buffer = _bufferLength; } }
contracts/Core/parameters/interfaces/IRandomNoManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IRandomNoManagerParams { /** * @notice changing buffer length between the states * @dev can be called only by the the address that has the governance role * @param _bufferLength updated value to be set for buffer */ function setBufferLength(uint8 _bufferLength) external; }
@openzeppelin/contracts/security/Pausable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
contracts/Core/parameters/child/VoteManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../interfaces/IVoteManagerParams.sol"; import "../ACL.sol"; import "../../storage/Constants.sol"; abstract contract VoteManagerParams is ACL, IVoteManagerParams, Constants { uint8 public buffer = 5; /// @notice maximum number of collections that can be assigned to the staker uint16 public toAssign = 3; /// @notice minimum amount of stake required to participate uint256 public minStake = 20000 * (10**18); /// @inheritdoc IVoteManagerParams function setMinStake(uint256 _minStake) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths minStake = _minStake; } /// @inheritdoc IVoteManagerParams function setToAssign(uint16 _toAssign) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths toAssign = _toAssign; } function setBufferLength(uint8 _bufferLength) external override onlyRole(GOVERNANCE_ROLE) { // slither-reason: Disabled across all params childs // as they are being called by governance contract only // and their before setting, we are emitting event // slither-disable-next-line events-maths buffer = _bufferLength; } }
contracts/Core/StateManager.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "./storage/Constants.sol"; /** @title StateManager * @notice StateManager manages the state of the network */ contract StateManager is Constants { /** * @notice a check to ensure the epoch value sent in the function is of the currect epoch */ modifier checkEpoch(uint32 epoch) { // slither-disable-next-line incorrect-equality require(epoch == _getEpoch(), "incorrect epoch"); _; } /** * @notice a check to ensure the function was called in the state specified */ modifier checkState(State state, uint8 buffer) { // slither-disable-next-line incorrect-equality require(state == _getState(buffer), "incorrect state"); _; } /** * @notice a check to ensure the function was not called in the state specified */ modifier notState(State state, uint8 buffer) { // slither-disable-next-line incorrect-equality require(state != _getState(buffer), "incorrect state"); _; } /** @notice a check to ensure the epoch value sent in the function is of the currect epoch * and was called in the state specified */ modifier checkEpochAndState( State state, uint32 epoch, uint8 buffer ) { // slither-disable-next-line incorrect-equality require(epoch == _getEpoch(), "incorrect epoch"); // slither-disable-next-line incorrect-equality require(state == _getState(buffer), "incorrect state"); _; } function _getEpoch() internal view returns (uint32) { return (uint32(block.timestamp) / (EPOCH_LENGTH)); } function _getState(uint8 buffer) internal view returns (State) { uint8 lowerLimit = buffer; uint16 upperLimit = EPOCH_LENGTH / NUM_STATES - buffer; // slither-disable-next-line timestamp,weak-prng if (block.timestamp % (EPOCH_LENGTH / NUM_STATES) > upperLimit || block.timestamp % (EPOCH_LENGTH / NUM_STATES) < lowerLimit) { return State.Buffer; } // slither-disable-next-line timestamp,weak-prng uint8 state = uint8(((block.timestamp) / (EPOCH_LENGTH / NUM_STATES)) % (NUM_STATES)); return State(state); } }
contracts/Core/storage/VoteStorage.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../../lib/Structs.sol"; contract VoteStorage { /// @notice mapping of stakerid -> commitment mapping(uint32 => Structs.Commitment) public commitments; // Epoch needs to be brought back due to AAR, each epoch would have different set of assets revealed /// @notice mapping of epoch -> stakerid -> assetid -> vote mapping(uint32 => mapping(uint32 => mapping(uint16 => uint256))) public votes; /// @notice mapping of epoch -> assetid -> weight mapping(uint32 => mapping(uint16 => uint256)) public totalInfluenceRevealed; /// @notice mapping of epoch -> assetid -> voteValue -> weight mapping(uint32 => mapping(uint16 => mapping(uint256 => uint256))) public voteWeights; /// @notice mapping of epoch-> stakerid->influence mapping(uint32 => mapping(uint32 => uint256)) public influenceSnapshot; /// @notice mapping of epoch-> stakerid->stake mapping(uint32 => mapping(uint32 => uint256)) public stakeSnapshot; /// @notice mapping of stakerid=> epochLastRevealed mapping(uint32 => uint32) public epochLastRevealed; /// @notice hash of last epoch and its block medians bytes32 public salt; /// @notice depth of a valid merkle tree uint256 public depth; // uint32 possible, pack if opp arise }
contracts/lib/Structs.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; library Structs { struct Commitment { uint32 epoch; bytes32 commitmentHash; } struct Staker { // Slot 1 bool acceptDelegation; bool isSlashed; uint8 commission; uint32 id; uint32 age; address _address; // Slot 2 address tokenAddress; uint32 epochFirstStakedOrLastPenalized; uint32 epochCommissionLastUpdated; // Slot 3 uint256 stake; uint256 stakerReward; } struct Lock { uint256 amount; //amount in sRZR/RZR uint256 unlockAfter; // Can be made uint32 later if packing is possible } struct BountyLock { uint32 redeemAfter; address bountyHunter; uint256 amount; //amount in RZR } struct Block { bool valid; uint32 proposerId; uint16[] ids; uint256 iteration; uint256 biggestStake; uint256[] medians; } struct Dispute { uint16 leafId; uint256 lastVisitedValue; uint256 accWeight; uint256 median; } struct Job { uint16 id; uint8 selectorType; // 0-1 uint8 weight; // 1-100 int8 power; string name; string selector; string url; } struct Collection { bool active; uint16 id; int8 power; uint32 tolerance; uint32 aggregationMethod; uint16[] jobIDs; string name; } struct AssignedAsset { uint16 leafId; uint256 value; } struct MerkleTree { Structs.AssignedAsset[] values; bytes32[][] proofs; bytes32 root; } }
contracts/Core/parameters/child/StakeManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../interfaces/IStakeManagerParams.sol"; import "../ACL.sol"; import "../../storage/Constants.sol"; abstract contract StakeManagerParams is ACL, IStakeManagerParams, Constants { struct SlashNums { // percent bounty from staker's stake to be received by the bounty hunter uint32 bounty; // percent RAZOR burn from staker's stake uint32 burn; // percent from staker's stake to be kept by staker uint32 keep; } /// @notice a boolean, if true, the default admin role can remove all the funds incase of emergency bool public escapeHatchEnabled = true; uint8 public buffer = 5; /// @notice the number of epochs for which the sRZRs are locked for calling unstake() uint16 public unstakeLockPeriod = 1; /// @notice the number of epochs for which the RAZORs are locked after initiating withdraw uint16 public withdrawLockPeriod = 1; /// @notice the number of epochs where staker/delegator needs to initiate withdraw uint16 public withdrawInitiationPeriod = 5; /** * @notice percentage stake penalty from the locked amount for extending unstake lock * incase withdrawInitiationPeriod was missed */ uint32 public resetUnstakeLockPenalty = 100_000; /// @notice maximum commission stakers can charge from delegators on their profits uint8 public maxCommission = 20; /// @notice maximum commission change a staker can do uint8 public deltaCommission = 3; /// @notice the number of epochs for which a staker cant change commission once set/change uint16 public epochLimitForUpdateCommission = 100; /// @notice slashing params being used if staker is slashed. Slash Penalty = bounty + burned + kept == 100% SlashNums public slashNums = SlashNums(500_000, 9_500_000, 0); /// @notice minimum amount of stake required to participate uint256 public minStake = 20000 * (10**18); /// @notice minimum amount of stake required to become a staker uint256 public minSafeRazor = 10000 * (10**18); /// @inheritdoc IStakeManagerParams function setSlashParams( uint32 _bounty, uint32 _burn, uint32 _keep ) external override onlyRole(GOVERNANCE_ROLE) { require(_bounty + _burn + _keep <= BASE_DENOMINATOR, "params sum exceeds denominator"); // slither-disable-next-line events-maths slashNums = SlashNums(_bounty, _burn, _keep); } /// @inheritdoc IStakeManagerParams function setDeltaCommission(uint8 _deltaCommission) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths deltaCommission = _deltaCommission; } /// @inheritdoc IStakeManagerParams function setEpochLimitForUpdateCommission(uint16 _epochLimitForUpdateCommission) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths epochLimitForUpdateCommission = _epochLimitForUpdateCommission; } /// @inheritdoc IStakeManagerParams function setUnstakeLockPeriod(uint16 _unstakeLockPeriod) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths unstakeLockPeriod = _unstakeLockPeriod; } /// @inheritdoc IStakeManagerParams function setWithdrawLockPeriod(uint16 _withdrawLockPeriod) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths withdrawLockPeriod = _withdrawLockPeriod; } /// @inheritdoc IStakeManagerParams function setWithdrawInitiationPeriod(uint16 _withdrawInitiationPeriod) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths withdrawInitiationPeriod = _withdrawInitiationPeriod; } /// @inheritdoc IStakeManagerParams function setResetUnstakeLockPenalty(uint32 _resetUnstakeLockPenalty) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths resetUnstakeLockPenalty = _resetUnstakeLockPenalty; } /// @inheritdoc IStakeManagerParams function setMinStake(uint256 _minStake) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths minStake = _minStake; } /// @inheritdoc IStakeManagerParams function setMinSafeRazor(uint256 _minSafeRazor) external override onlyRole(GOVERNANCE_ROLE) { require(_minSafeRazor <= minStake, "minSafeRazor beyond minStake"); // slither-disable-next-line events-maths minSafeRazor = _minSafeRazor; } /// @inheritdoc IStakeManagerParams function setMaxCommission(uint8 _maxCommission) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths maxCommission = _maxCommission; } /// @inheritdoc IStakeManagerParams function disableEscapeHatch() external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths escapeHatchEnabled = false; } function setBufferLength(uint8 _bufferLength) external override onlyRole(GOVERNANCE_ROLE) { // slither-reason: Disabled across all params childs // as they are being called by governance contract only // and their before setting, we are emitting event // slither-disable-next-line events-maths buffer = _bufferLength; } }
contracts/mocks/InitializableMock.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../Initializable.sol"; /** * @title InitializableMock * @dev This contract is a mock to test initializable functionality */ contract InitializableMock is Initializable { bool public initializerRan; function initializeNested() external initializer { initialize(); } function initialize() public initializer { initializerRan = true; } }
contracts/Core/storage/StakeStorage.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../../lib/Structs.sol"; contract StakeStorage { enum LockType { Unstake, Withdraw } /// @notice total number of stakers // slither-disable-next-line constable-states uint32 public numStakers; /// @notice total number of bounties given out // slither-disable-next-line constable-states uint32 public bountyCounter; /// @notice mapping of staker address -> staker id info mapping(address => uint32) public stakerIds; /// @notice mapping of staker id -> staker info mapping(uint32 => Structs.Staker) public stakers; /// @notice mapping of staker/delegator address -> staker sRZR address -> LockType -> Lock info mapping(address => mapping(address => mapping(LockType => Structs.Lock))) public locks; /// @notice mapping of bounty id -> bounty lock info mapping(uint32 => Structs.BountyLock) public bountyLocks; /// @notice maturity calculation for each index = [math.floor(math.sqrt(i*10000)/2) for i in range(1,100)] uint16[101] public maturities = [ 50, 70, 86, 100, 111, 122, 132, 141, 150, 158, 165, 173, 180, 187, 193, 200, 206, 212, 217, 223, 229, 234, 239, 244, 250, 254, 259, 264, 269, 273, 278, 282, 287, 291, 295, 300, 304, 308, 312, 316, 320, 324, 327, 331, 335, 339, 342, 346, 350, 353, 357, 360, 364, 367, 370, 374, 377, 380, 384, 387, 390, 393, 396, 400, 403, 406, 409, 412, 415, 418, 421, 424, 427, 430, 433, 435, 438, 441, 444, 447, 450, 452, 455, 458, 460, 463, 466, 469, 471, 474, 476, 479, 482, 484, 487, 489, 492, 494, 497, 500, 502 ]; }
contracts/Pause.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "@openzeppelin/contracts/security/Pausable.sol"; import "./Core/parameters/ACL.sol"; import "./Core/storage/Constants.sol"; contract Pause is Pausable, ACL, Constants { function pause() external onlyRole(PAUSE_ROLE) { Pausable._pause(); } function unpause() external onlyRole(PAUSE_ROLE) { Pausable._unpause(); } }
contracts/Delegator.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "./Core/StateManager.sol"; import "./Core/interface/ICollectionManager.sol"; import "./IDelegator.sol"; import "./randomNumber/IRandomNoClient.sol"; import "./Core/parameters/ACL.sol"; import "./Core/storage/Constants.sol"; import "./Pause.sol"; /** @title Delegator * @notice Delegator acts as a bridge between the client and the protocol */ contract Delegator is ACL, StateManager, Pause, IDelegator { ICollectionManager public collectionManager; IRandomNoClient public randomNoManager; /// @inheritdoc IDelegator function updateAddress(address newDelegateAddress, address newRandomNoManagerAddress) external override onlyRole(DEFAULT_ADMIN_ROLE) { require(newDelegateAddress != address(0x0) && newRandomNoManagerAddress != address(0x0), "Zero Address check"); collectionManager = ICollectionManager(newDelegateAddress); randomNoManager = IRandomNoClient(newRandomNoManagerAddress); } /// @inheritdoc IDelegator function register() external override whenNotPaused returns (bytes32) { return randomNoManager.register(); } /// @inheritdoc IDelegator function getActiveCollections() external view override whenNotPaused returns (uint16[] memory) { return collectionManager.getActiveCollections(); } /// @inheritdoc IDelegator function getCollectionStatus(uint16 _id) external view override whenNotPaused returns (bool) { return collectionManager.getCollectionStatus(_id); } /// @inheritdoc IDelegator function getCollectionID(bytes32 _hname) external view override whenNotPaused returns (uint16) { return collectionManager.getCollectionID(_hname); } /// @inheritdoc IDelegator function getResult(bytes32 _name) external view override whenNotPaused returns (uint256, int8) { return collectionManager.getResult(_name); } /// @inheritdoc IDelegator function getResultFromID(uint16 _id) external view override whenNotPaused returns (uint256, int8) { return collectionManager.getResultFromID(_id); } /// @inheritdoc IDelegator function getRandomNumber(bytes32 requestId) external view override whenNotPaused returns (uint256) { return randomNoManager.getRandomNumber(requestId); } /// @inheritdoc IDelegator function getGenericRandomNumberOfLastEpoch() external view override whenNotPaused returns (uint256) { return randomNoManager.getGenericRandomNumberOfLastEpoch(); } /// @inheritdoc IDelegator function getGenericRandomNumber(uint32 _epoch) external view override whenNotPaused returns (uint256) { return randomNoManager.getGenericRandomNumber(_epoch); } }
@openzeppelin/contracts/token/ERC20/ERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; } _balances[to] += amount; emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
contracts/Core/parameters/interfaces/IStakeManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IStakeManagerParams { /** * @notice changing slashing parameters * @dev can be called only by the the address that has the governance role * @param _bounty updated percent value to be set for bounty * @param _burn updated percent value to be set for burn * @param _keep updated percent value to be set for keep */ function setSlashParams( uint32 _bounty, uint32 _burn, uint32 _keep ) external; /** * @notice changing the number of epochs for which the RAZORs are locked after initiating withdraw * @dev can be called only by the the address that has the governance role * @param _withdrawLockPeriod updated value to be set for withdrawLockPeriod */ function setWithdrawLockPeriod(uint16 _withdrawLockPeriod) external; /** * @notice changing the number of epochs for which the sRZRs are locked for calling unstake() * @dev can be called only by the the address that has the governance role * @param _unstakeLockPeriod updated value to be set for unstakeLockPeriod */ function setUnstakeLockPeriod(uint16 _unstakeLockPeriod) external; /** * @notice changing the number of epochs where staker/delegator needs to initiate withdraw * @dev can be called only by the the address that has the governance role * @param _withdrawInitiationPeriod updated value to be set for withdrawInitiationPeriod */ function setWithdrawInitiationPeriod(uint16 _withdrawInitiationPeriod) external; /** * @notice changing percentage stake penalty from the locked amount for extending unstake lock * incase withdrawInitiationPeriod was missed * @dev can be called only by the the address that has the governance role * @param _resetUnstakePenalty updated value to be set for resetUnstakePenalty */ function setResetUnstakeLockPenalty(uint32 _resetUnstakePenalty) external; /** * @notice changing minimum amount that to be staked for participation * @dev can be called only by the the address that has the governance role * @param _minStake updated value to be set for minStake */ function setMinStake(uint256 _minStake) external; /** * @notice changing minimum amount that to be staked to become a staker * @dev can be called only by the the address that has the governance role * @param _minSafeRazor updated value to be set for minSafeRazor */ function setMinSafeRazor(uint256 _minSafeRazor) external; /** * @notice changing maximum commission stakers can charge from delegators on their profits * @dev can be called only by the the address that has the governance role * @param _maxCommission updated value to be set for maxCommission */ function setMaxCommission(uint8 _maxCommission) external; /** * @notice changing maximum commission change a staker can do * @dev can be called only by the the address that has the governance role * @param _deltaCommission updated value to be set for deltaCommission */ function setDeltaCommission(uint8 _deltaCommission) external; /** * @notice changing the number of epochs for which a staker cant change commission once set/change * @dev can be called only by the the address that has the governance role * @param _epochLimitForUpdateCommission updated value to be set for epochLimitForUpdateCommission */ function setEpochLimitForUpdateCommission(uint16 _epochLimitForUpdateCommission) external; /** * @notice sets escape hatch to false permanently * @dev can be called only by the the address that has the governance role */ function disableEscapeHatch() external; /** * @notice changing buffer length between the states * @dev can be called only by the the address that has the governance role * @param _bufferLength updated value to be set for buffer */ function setBufferLength(uint8 _bufferLength) external; }
contracts/randomNumber/RandomNoStorage.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; contract RandomNoStorage { /// @notice mapping of client address => nonce mapping(address => uint32) public nonce; /// @notice mapping of requestId => epoch mapping(bytes32 => uint32) public requests; /// @notice mapping of epoch => secrets mapping(uint32 => bytes32) public secrets; }
contracts/Core/VoteManager.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "./interface/IVoteManager.sol"; import "./interface/IStakeManager.sol"; import "./interface/IRewardManager.sol"; import "./interface/IBlockManager.sol"; import "./interface/ICollectionManager.sol"; import "./storage/VoteStorage.sol"; import "./parameters/child/VoteManagerParams.sol"; import "./StateManager.sol"; import "../Initializable.sol"; import "../lib/MerklePosAware.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; /** @title VoteManager * @notice VoteManager manages the commitments of votes of the stakers */ contract VoteManager is Initializable, VoteStorage, StateManager, VoteManagerParams, IVoteManager { IStakeManager public stakeManager; IRewardManager public rewardManager; IBlockManager public blockManager; ICollectionManager public collectionManager; /** * @dev Emitted when a staker commits * @param epoch epoch when the commitment was sent * @param stakerId id of the staker that committed * @param commitment the staker's commitment * @param timestamp time when the commitment was set for the staker */ event Committed(uint32 epoch, uint32 indexed stakerId, bytes32 commitment, uint256 timestamp); /** * @dev Emitted when a staker reveals * @param epoch epoch when the staker revealed * @param stakerId id of the staker that reveals * @param influence influence of the staker * @param values of the collections assigned to the staker * @param timestamp time when the staker revealed */ event Revealed(uint32 epoch, uint32 indexed stakerId, uint256 influence, Structs.AssignedAsset[] values, uint256 timestamp); /** * @dev Emitted when bountyHunter snitch the staker * @param epoch epoch when the bountyHunter snitch the staker * @param stakerId id of the staker that is snitched * @param bountyHunter address who will snitch the staker */ event Snitch(uint32 epoch, uint32 indexed stakerId, address indexed bountyHunter); /** * @param stakeManagerAddress The address of the StakeManager contract * @param rewardManagerAddress The address of the RewardManager contract * @param blockManagerAddress The address of the BlockManager contract * @param collectionManagerAddress The address of the CollectionManager contract */ function initialize( address stakeManagerAddress, address rewardManagerAddress, address blockManagerAddress, address collectionManagerAddress ) external initializer onlyRole(DEFAULT_ADMIN_ROLE) { stakeManager = IStakeManager(stakeManagerAddress); rewardManager = IRewardManager(rewardManagerAddress); blockManager = IBlockManager(blockManagerAddress); collectionManager = ICollectionManager(collectionManagerAddress); } /** * @notice stakers query the jobs in collection, aggregate and instead of revealing them instantly, * they need to submit a hash of their results which becomes their commitment and send it to the protocol * @dev After query and aggregation is done, the staker would have to construct a merkle tree of their votes. * * The commitment sent by the staker is hash of root of the merkle tree and seed, which * is the hash of the salt and the staker's secret. * * Collection allocation of each staker is done using seed and the staker would know in commit itself their allocations * but wouldn't know other staker's allocation unless they have their seed. Hence, it is advisable to fetch results for * only those collections that they have been assigned and set rest to 0 and construct a merkle tree accordingly * * Before the staker's commitment is registered, the staker confirms the block of the previous epoch incase the initial * proposer had not confirmed the block. The staker then gets the block reward if confirmed by the staker and is then * given out penalties based on their votes in the previous epoch or incase of inactivity. * * @param epoch epoch when the commitment was sent * @param commitment the commitment */ function commit(uint32 epoch, bytes32 commitment) external initialized checkEpochAndState(State.Commit, epoch, buffer) { require(commitment != 0x0, "Invalid commitment"); uint32 stakerId = stakeManager.getStakerId(msg.sender); require(!stakeManager.getStaker(stakerId).isSlashed, "VM : staker is slashed"); require(stakerId > 0, "Staker does not exist"); require(commitments[stakerId].epoch != epoch, "already commited"); // Switch to call confirm block only when block in previous epoch has not been confirmed // and if previous epoch do have proposed blocks // slither-disable-next-line reentrancy-events,reentrancy-no-eth if (!blockManager.isBlockConfirmed(epoch - 1)) { blockManager.confirmPreviousEpochBlock(stakerId); } // slither-disable-next-line reentrancy-events,reentrancy-no-eth rewardManager.givePenalties(epoch, stakerId); uint256 thisStakerStake = stakeManager.getStake(stakerId); if (thisStakerStake >= minStake) { commitments[stakerId].epoch = epoch; commitments[stakerId].commitmentHash = commitment; emit Committed(epoch, stakerId, commitment, block.timestamp); } } /** * @notice staker reveal the votes that they had committed to the protocol in the commit state. * Stakers would only reveal the collections they have been allocated, the rest of their votes wont matter * @dev stakers would need to submit their votes in accordance of how they were assigned to the staker. * for example, if they are assigned the following ids: [2,5,4], they would to send their votes in the following order only * The votes of other ids dont matter but they should not be passed in the values. * So staker would have to pass the proof path of the assigned values of the merkle tree, root of the merkle tree and * the values being revealed into a struct in the Structs.MerkleTree format. * @param epoch epoch when the revealed their votes * @param tree the merkle tree struct of the staker * @param signature staker's signature on the messageHash which calculates * the secret using which seed would be calculated and thereby checking for collection allocation */ function reveal( uint32 epoch, Structs.MerkleTree memory tree, bytes memory signature ) external initialized checkEpochAndState(State.Reveal, epoch, buffer) { uint32 stakerId = stakeManager.getStakerId(msg.sender); require(stakerId > 0, "Staker does not exist"); require(commitments[stakerId].epoch == epoch, "not committed in this epoch"); require(tree.values.length == toAssign, "values length mismatch"); bytes32 messageHash = keccak256(abi.encodePacked(msg.sender, epoch, block.chainid, "razororacle")); require(ECDSA.recover(ECDSA.toEthSignedMessageHash(messageHash), signature) == msg.sender, "invalid signature"); bytes32 secret = keccak256(signature); bytes32 seed = keccak256(abi.encode(salt, secret)); require(keccak256(abi.encode(tree.root, seed)) == commitments[stakerId].commitmentHash, "incorrect secret/value"); { uint256 stakerStake = stakeManager.getStake(stakerId); require(stakerStake >= minStake, "stake below minimum"); stakeSnapshot[epoch][stakerId] = stakerStake; } //below line also avoid double reveal attack since once revealed, commitment has will be set to 0x0 commitments[stakerId].commitmentHash = 0x0; uint256 influence = stakeManager.getInfluence(stakerId); influenceSnapshot[epoch][stakerId] = influence; uint16 max = collectionManager.getNumActiveCollections(); for (uint16 i = 0; i < tree.values.length; i++) { require(_isAssetAllotedToStaker(seed, i, max, tree.values[i].leafId), "Revealed asset not alloted"); // If Job Not Revealed before, like its not in same reveal batch of this // As it would be redundant to check // please note due to this job result cant be zero if (votes[epoch][stakerId][tree.values[i].leafId] == 0) { // Check if asset value is zero // Reason for doing this is, staker can vote 0 for assigned coll, and get away with penalties" require(tree.values[i].value != 0, "0 vote for assigned coll"); // reason to ignore : its internal lib not a external call // slither-disable-next-line calls-loop require( MerklePosAware.verify( tree.proofs[i], tree.root, keccak256(abi.encode(tree.values[i].value)), tree.values[i].leafId, depth, collectionManager.getNumActiveCollections() ), "invalid merkle proof" ); votes[epoch][stakerId][tree.values[i].leafId] = tree.values[i].value; voteWeights[epoch][tree.values[i].leafId][tree.values[i].value] = voteWeights[epoch][tree.values[i].leafId][tree.values[i].value] + influence; totalInfluenceRevealed[epoch][tree.values[i].leafId] = totalInfluenceRevealed[epoch][tree.values[i].leafId] + influence; } } epochLastRevealed[stakerId] = epoch; emit Revealed(epoch, stakerId, influence, tree.values, block.timestamp); } //bounty hunter revealing secret in commit state /** * @notice incase the staker's secret and root of the merkle tree is leaked before the staker reveals, * a bounty hunter can snitch on the staker and reveal the root and secret to the protocol * @dev when the staker is correctly snitched, their stake is slashed and the bounty hunter receives * a part of their stake based on the Slash Nums parameters. A staker can be snitched only in the commit state * @param epoch epoch when the bounty hunter snitched. * @param root of the staker's merkle tree * @param secret secret of the staker being snitched * @param stakerAddress the address of the staker */ function snitch( uint32 epoch, bytes32 root, bytes32 secret, address stakerAddress ) external initialized checkEpochAndState(State.Commit, epoch, buffer) { require(msg.sender != stakerAddress, "cant snitch on yourself"); uint32 thisStakerId = stakeManager.getStakerId(stakerAddress); require(thisStakerId > 0, "Staker does not exist"); require(commitments[thisStakerId].epoch == epoch, "not committed in this epoch"); // avoid innocent staker getting slashed due to empty secret require(secret != 0x0, "secret cannot be empty"); bytes32 seed = keccak256(abi.encode(salt, secret)); require(keccak256(abi.encode(root, seed)) == commitments[thisStakerId].commitmentHash, "incorrect secret/value"); //below line also avoid double reveal attack since once revealed, commitment has will be set to 0x0 commitments[thisStakerId].commitmentHash = 0x0; emit Snitch(epoch, thisStakerId, msg.sender); stakeManager.slash(epoch, thisStakerId, msg.sender); } /// @inheritdoc IVoteManager function storeSalt(bytes32 _salt) external override initialized onlyRole(SALT_MODIFIER_ROLE) { salt = _salt; } /// @inheritdoc IVoteManager function storeDepth(uint256 _depth) external override initialized onlyRole(DEPTH_MODIFIER_ROLE) { depth = _depth; } function getCommitment(uint32 stakerId) external view returns (Structs.Commitment memory commitment) { //epoch -> stakerid -> commitment return (commitments[stakerId]); } /// @inheritdoc IVoteManager function getVoteValue( uint32 epoch, uint32 stakerId, uint16 leafId ) external view override returns (uint256) { //epoch -> stakerid -> asserId return votes[epoch][stakerId][leafId]; } /// @inheritdoc IVoteManager function getVoteWeight( uint32 epoch, uint16 leafId, uint256 voteValue ) external view override returns (uint256) { //epoch -> leafId -> voteValue -> weight return (voteWeights[epoch][leafId][voteValue]); } /// @inheritdoc IVoteManager function getInfluenceSnapshot(uint32 epoch, uint32 stakerId) external view override returns (uint256) { //epoch -> stakerId return (influenceSnapshot[epoch][stakerId]); } /// @inheritdoc IVoteManager function getStakeSnapshot(uint32 epoch, uint32 stakerId) external view override returns (uint256) { //epoch -> stakerId return (stakeSnapshot[epoch][stakerId]); } /// @inheritdoc IVoteManager function getTotalInfluenceRevealed(uint32 epoch, uint16 leafId) external view override returns (uint256) { return (totalInfluenceRevealed[epoch][leafId]); } /// @inheritdoc IVoteManager function getEpochLastCommitted(uint32 stakerId) external view override returns (uint32) { return commitments[stakerId].epoch; } /// @inheritdoc IVoteManager function getEpochLastRevealed(uint32 stakerId) external view override returns (uint32) { return epochLastRevealed[stakerId]; } /// @inheritdoc IVoteManager function getSalt() external view override returns (bytes32) { return salt; } /** * @dev an internal function used to check whether the particular collection was allocated to the staker * @param seed hash of salt and staker's secret * @param iterationOfLoop positioning of the collection allocation sequence * @param leafId leafId of the collection that is being checked for allotment */ function _isAssetAllotedToStaker( bytes32 seed, uint16 iterationOfLoop, uint16 max, uint16 leafId ) internal view initialized returns (bool) { // max= numAssets, prng_seed = seed+ iteration of for loop if (_prng(keccak256(abi.encode(seed, iterationOfLoop)), max) == leafId) return true; return false; } /** * @dev an internal function used by _isAssetAllotedToStaker to check for allocation * @param prngSeed hash of seed and exact position in sequence * @param max total number of active collections */ function _prng(bytes32 prngSeed, uint256 max) internal pure returns (uint256) { uint256 sum = uint256(prngSeed); return (sum % max); } }
@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
contracts/Core/parameters/child/RewardManagerParams.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../interfaces/IRewardManagerParams.sol"; import "../ACL.sol"; import "../../storage/Constants.sol"; abstract contract RewardManagerParams is ACL, IRewardManagerParams, Constants { /// @notice percentage stake penalty to be given out for inactivity uint32 public penaltyNotRevealNum = 1000; /// @notice percentage age penalty to be given out for inactivity uint32 public penaltyAgeNotRevealNum = 100_000; /// @notice maximum age a staker can have uint32 public maxAge = 100 * 10000; /// @notice reward given to staker whose block is confirmed uint256 public blockReward = 100 * (10**18); /// @notice maximum percentage deviation allowed from medians for all collections uint32 public maxTolerance = 1_000_000; /// @notice maximum commission stakers can charge from delegators on their profits uint8 public maxCommission = 20; /// @inheritdoc IRewardManagerParams function setPenaltyNotRevealNum(uint32 _penaltyNotRevealNumerator) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths penaltyNotRevealNum = _penaltyNotRevealNumerator; } /// @inheritdoc IRewardManagerParams function setPenaltyAgeNotRevealNum(uint32 _penaltyAgeNotRevealNumerator) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths penaltyAgeNotRevealNum = _penaltyAgeNotRevealNumerator; } /// @inheritdoc IRewardManagerParams function setBlockReward(uint256 _blockReward) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths blockReward = _blockReward; } /// @inheritdoc IRewardManagerParams function setMaxAge(uint32 _maxAge) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths maxAge = _maxAge; } /// @inheritdoc IRewardManagerParams function setMaxTolerance(uint32 _maxTolerance) external override onlyRole(GOVERNANCE_ROLE) { // slither-reason: Disabled across all params childs // as they are being called by governance contract only // and their before setting, we are emitting event // slither-disable-next-line events-maths maxTolerance = _maxTolerance; } /// @inheritdoc IRewardManagerParams function setMaxCommission(uint8 _maxCommission) external override onlyRole(GOVERNANCE_ROLE) { // slither-disable-next-line events-maths maxCommission = _maxCommission; } }
contracts/tokenization/StakedToken.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "./IStakedToken.sol"; import "../Core/interface/IStakeManager.sol"; contract StakedToken is ERC20, IStakedToken { address private _owner; uint32 public stakerID; IStakeManager public stakeManager; /** * @notice Mapping to store the amount of RZR delegated or staked by user * hence at any time we can calculate gain = (current Rel * sRZRamount) - ((razorDeposited/balOfsRZR()) * sRZRamount) * razorDeposited/balOfsRZR() indicates, for 1 sRZR, how much you had put in */ mapping(address => uint256) public razorDeposited; modifier onlyOwner() { require(_owner == msg.sender, "Ownable: caller is not the owner"); _; } /** * @dev unique ERC20 sToken contract is deployed for every new staker that stakes into the protocol * @param stakeManagerAddress address of the stake manager contract * @param _stakerID the id of staker for whom the sToken is being deployed */ constructor(address stakeManagerAddress, uint32 _stakerID) ERC20("sRZR", "sRZR") { require(stakeManagerAddress != address(0), "zero Address Check"); _owner = stakeManagerAddress; stakeManager = IStakeManager(stakeManagerAddress); stakerID = _stakerID; } /// @inheritdoc IStakedToken function mint( address account, uint256 amount, uint256 _razorDeposited ) external override onlyOwner returns (bool) { razorDeposited[account] = razorDeposited[account] + _razorDeposited; _mint(account, amount); return true; } /// @inheritdoc IStakedToken function burn(address account, uint256 amount) external override onlyOwner returns (bool) { _burn(account, amount); return true; } /// @inheritdoc IStakedToken function getRZRDeposited(address user, uint256 sAmount) public view override returns (uint256) { require(balanceOf(user) >= sAmount, "Amount Exceeds Balance"); return ((sAmount * razorDeposited[user]) / balanceOf(user)); } /** * @dev an internal function that handles the amount os razor deposited based on sRZR token transfer. * If sRZR is transferred from to another account, razor deposited should also be transferred * @param from address from where sRZR is being transferred from * @param to address where sRZR is being transferred to * @param amount amount sRZR being transferred */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override { //mint : addition, would happen in case of delegate or stake //burn : subtraction, would happeen when staker calls withdraw //transfer : add and sub // Mint case is handled up only if (to == address(0)) { //Burn uint256 propotionalRazorContribution = getRZRDeposited(from, amount); razorDeposited[from] = razorDeposited[from] - propotionalRazorContribution; } else if (from != address(0)) { uint256 propotionalRazorContribution = getRZRDeposited(from, amount); razorDeposited[from] = razorDeposited[from] - propotionalRazorContribution; razorDeposited[to] = razorDeposited[to] + propotionalRazorContribution; } stakeManager.srzrTransfer(from, to, amount, stakerID); } }
contracts/Core/parameters/Governance.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../../Initializable.sol"; import "./interfaces/IBlockManagerParams.sol"; import "./interfaces/IRewardManagerParams.sol"; import "./interfaces/IRandomNoManagerParams.sol"; import "./interfaces/IStakeManagerParams.sol"; import "./interfaces/IVoteManagerParams.sol"; import "./interfaces/ICollectionManagerParams.sol"; import "./../interface/IStakeManager.sol"; import "../storage/Constants.sol"; import "./ACL.sol"; // slither-reason : Disabled as slither is suggesting to have params interfaces to be inherited here // Though function signatures are same, meaning is diff // also two interfaces are going to have some common functions in this case // slither-disable-next-line missing-inheritance contract Governance is Initializable, ACL, Constants { IBlockManagerParams public blockManagerParams; IRewardManagerParams public rewardManagerParams; IStakeManagerParams public stakeManagerParams; IVoteManagerParams public voteManagerParams; ICollectionManagerParams public collectionManagerParams; IStakeManager public stakeManager; IRandomNoManagerParams public randomNoManagerParams; bytes32 public constant GOVERNER_ROLE = 0x704c992d358ec8f6051d88e5bd9f92457afedcbc3e2d110fcd019b5eda48e52e; /** * @notice emitted when any governance parameter value changes. * @param admin address of the admin * @param parameterName the parameter that is changing * @param valueChangedTo new value of the parameter * @param timestamp the exact time the parameter change took place */ event ParameterChanged(address indexed admin, string parameterName, uint256 valueChangedTo, uint256 timestamp); /** * @param blockManagerAddress The address of the BlockManager contract * @param rewardManagerAddress The address of the RewardManager contract * @param stakeManagerAddress The address of the StakeManager contract * @param voteManagerAddress The address of the VoteManager contract * @param collectionManagerAddress The address of the CollectionManager contract */ function initialize( address blockManagerAddress, address rewardManagerAddress, address stakeManagerAddress, address voteManagerAddress, address collectionManagerAddress, address randomNoManagerAddress ) external initializer onlyRole(DEFAULT_ADMIN_ROLE) { blockManagerParams = IBlockManagerParams(blockManagerAddress); rewardManagerParams = IRewardManagerParams(rewardManagerAddress); stakeManagerParams = IStakeManagerParams(stakeManagerAddress); voteManagerParams = IVoteManagerParams(voteManagerAddress); collectionManagerParams = ICollectionManagerParams(collectionManagerAddress); stakeManager = IStakeManager(stakeManagerAddress); randomNoManagerParams = IRandomNoManagerParams(randomNoManagerAddress); } /** * @notice changing the percentage stake penalty to be given out for inactivity * @dev can be called only by the the address that has the governer role * @param _penaltyNotRevealNumerator updated value to be set for penaltyNotRevealNumerator */ function setPenaltyNotRevealNum(uint32 _penaltyNotRevealNumerator) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "penaltyNotRevealNum", _penaltyNotRevealNumerator, block.timestamp); rewardManagerParams.setPenaltyNotRevealNum(_penaltyNotRevealNumerator); } /** * @notice changing the percentage age penalty to be given out for inactivity * @dev can be called only by the the address that has the governer role * @param _penaltyAgeNotRevealNumerator updated value to be set for penaltyAgeNotRevealNumerator */ function setPenaltyAgeNotRevealNum(uint32 _penaltyAgeNotRevealNumerator) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "penaltyAgeNotRevealNum", _penaltyAgeNotRevealNumerator, block.timestamp); rewardManagerParams.setPenaltyAgeNotRevealNum(_penaltyAgeNotRevealNumerator); } /** * @notice changing slashing parameters * @dev can be called only by the the address that has the governer role * @param _bounty updated percent value to be set for bounty * @param _burn updated percent value to be set for burn * @param _keep updated percent value to be set for keep */ function setSlashParams( uint32 _bounty, uint32 _burn, uint32 _keep ) external initialized onlyRole(GOVERNER_ROLE) { require(_bounty + _burn + _keep <= BASE_DENOMINATOR, "Slash nums addtion exceeds 10mil"); emit ParameterChanged(msg.sender, "bountySlashNum", _bounty, block.timestamp); emit ParameterChanged(msg.sender, "burnSlashNum", _burn, block.timestamp); emit ParameterChanged(msg.sender, "keepSlashNum", _keep, block.timestamp); stakeManagerParams.setSlashParams(_bounty, _burn, _keep); } /** * @notice changing the number of epochs for which the sRZRs are locked for calling unstake() * @dev can be called only by the the address that has the governer role * @param _unstakeLockPeriod updated value to be set for unstakeLockPeriod */ function setUnstakeLockPeriod(uint16 _unstakeLockPeriod) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "unstakeLockPeriod", _unstakeLockPeriod, block.timestamp); stakeManagerParams.setUnstakeLockPeriod(_unstakeLockPeriod); } /** * @notice changing the number of epochs for which the RAZORs are locked after initiating withdraw * @dev can be called only by the the address that has the governer role * @param _withdrawLockPeriod updated value to be set for withdrawLockPeriod */ function setWithdrawLockPeriod(uint16 _withdrawLockPeriod) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "withdrawLockPeriod", _withdrawLockPeriod, block.timestamp); stakeManagerParams.setWithdrawLockPeriod(_withdrawLockPeriod); } /** * @notice changing the number of epochs where staker/delegator needs to initiate withdraw * @dev can be called only by the the address that has the governer role * @param _withdrawInitiationPeriod updated value to be set for withdrawInitiationPeriod */ function setWithdrawInitiationPeriod(uint16 _withdrawInitiationPeriod) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "withdrawInitiationPeriod", _withdrawInitiationPeriod, block.timestamp); stakeManagerParams.setWithdrawInitiationPeriod(_withdrawInitiationPeriod); } /** * @notice changing percentage stake penalty from the locked amount for extending unstake lock * incase withdrawInitiationPeriod was missed * @dev can be called only by the the address that has the governer role * @param _extendLockPenalty updated value to be set for extendLockPenalty */ function setResetUnstakeLockPenalty(uint32 _extendLockPenalty) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "extendLockPenalty", _extendLockPenalty, block.timestamp); stakeManagerParams.setResetUnstakeLockPenalty(_extendLockPenalty); } /** * @notice changing the maximum number of best proposed blocks to be considered for dispute * @dev can be called only by the the address that has the governer role * @param _maxAltBlocks updated value to be set for maxAltBlocks */ function setMaxAltBlocks(uint8 _maxAltBlocks) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "maxAltBlocks", _maxAltBlocks, block.timestamp); blockManagerParams.setMaxAltBlocks(_maxAltBlocks); } /** * @notice changing minimum amount that to be staked for participation * @dev can be called only by the the address that has the governer role * @param _minStake updated value to be set for minStake */ function setMinStake(uint256 _minStake) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "minStake", _minStake, block.timestamp); stakeManagerParams.setMinStake(_minStake); voteManagerParams.setMinStake(_minStake); blockManagerParams.setMinStake(_minStake); } /** * @notice changing minimum amount that to be staked to become a staker * @dev can be called only by the the address that has the governer role * @param _minSafeRazor updated value to be set for minSafeRazor */ function setMinSafeRazor(uint256 _minSafeRazor) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "minSafeRazor", _minSafeRazor, block.timestamp); stakeManagerParams.setMinSafeRazor(_minSafeRazor); } /** * @notice changing the block reward given out to stakers * @dev can be called only by the the address that has the governer role * @param _blockReward updated value to be set for blockReward */ function setBlockReward(uint256 _blockReward) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "blockReward", _blockReward, block.timestamp); blockManagerParams.setBlockReward(_blockReward); rewardManagerParams.setBlockReward(_blockReward); } /** * @notice changing the maximum age a staker can have * @dev can be called only by the the address that has the governer role * @param _maxAge updated value to be set for maxAge */ function setMaxAge(uint32 _maxAge) external initialized onlyRole(GOVERNER_ROLE) { require(_maxAge <= stakeManager.maturitiesLength() * 10000, "Invalid Max Age Update"); emit ParameterChanged(msg.sender, "maxAge", _maxAge, block.timestamp); rewardManagerParams.setMaxAge(_maxAge); } /** * @notice changing maximum commission stakers can charge from delegators on their profits * @dev can be called only by the the address that has the governance role * @param _maxCommission updated value to be set for maxCommission */ function setMaxCommission(uint8 _maxCommission) external initialized onlyRole(GOVERNER_ROLE) { require(_maxCommission <= 100, "Invalid Max Commission Update"); emit ParameterChanged(msg.sender, "maxCommission", _maxCommission, block.timestamp); stakeManagerParams.setMaxCommission(_maxCommission); rewardManagerParams.setMaxCommission(_maxCommission); } /** * @notice sets escape hatch to false permanently * @dev can be called only by the the address that has the governer role */ function disableEscapeHatch() external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "escapeHatchEnabled", 0, block.timestamp); stakeManagerParams.disableEscapeHatch(); } /** * @notice changing maximum commission change a staker can do * @dev can be called only by the the address that has the governance role * @param _deltaCommission updated value to be set for deltaCommission */ function setDeltaCommission(uint8 _deltaCommission) external initialized onlyRole(GOVERNER_ROLE) { require(_deltaCommission <= 100, "deltaCommission exceeds 100"); emit ParameterChanged(msg.sender, "deltaCommission", _deltaCommission, block.timestamp); stakeManagerParams.setDeltaCommission(_deltaCommission); } /** * @notice changing the number of epochs for which a staker cant change commission once set/change * @dev can be called only by the the address that has the governance role * @param _epochLimitForUpdateCommission updated value to be set for epochLimitForUpdateCommission */ function setEpochLimitForUpdateCommission(uint16 _epochLimitForUpdateCommission) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "epochLimitForUpdateCommission", _epochLimitForUpdateCommission, block.timestamp); stakeManagerParams.setEpochLimitForUpdateCommission(_epochLimitForUpdateCommission); } /** * @notice changing the maximum percentage deviation allowed from medians for all collections * @dev can be called only by the the address that has the governance role * @param _maxTolerance updated value for maxTolerance */ function setMaxTolerance(uint32 _maxTolerance) external initialized onlyRole(GOVERNER_ROLE) { require(_maxTolerance <= BASE_DENOMINATOR, "maxTolerance exceeds baseDenom"); emit ParameterChanged(msg.sender, "maxTolerance", _maxTolerance, block.timestamp); collectionManagerParams.setMaxTolerance(_maxTolerance); rewardManagerParams.setMaxTolerance(_maxTolerance); } /** * @notice changing maximum number of collections that can be assigned to the staker * @dev can be called only by the the address that has the governance role * @param _toAssign updated value to be set for toAssign */ function setToAssign(uint16 _toAssign) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "toAssign", _toAssign, block.timestamp); voteManagerParams.setToAssign(_toAssign); } /** * @notice chnaging the buffer length of all the contracts * @dev can be called only by the the address that has the governance role * @param _bufferLength updated value to be set for buffer */ function setBufferLength(uint8 _bufferLength) external initialized onlyRole(GOVERNER_ROLE) { emit ParameterChanged(msg.sender, "_bufferLength", _bufferLength, block.timestamp); blockManagerParams.setBufferLength(_bufferLength); voteManagerParams.setBufferLength(_bufferLength); collectionManagerParams.setBufferLength(_bufferLength); randomNoManagerParams.setBufferLength(_bufferLength); } }
contracts/Core/interface/IRewardManager.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../../lib/Structs.sol"; interface IRewardManager { /** * @notice gives penalty to stakers for failing to reveal or * reveal value deviations * @param stakerId The id of staker currently in consideration * @param epoch the epoch value */ function givePenalties(uint32 epoch, uint32 stakerId) external; /** * @notice The function gives block reward for one valid proposer in the * previous epoch by increasing stake of staker * called from confirmBlock function of BlockManager contract. Commission * from the delegator's pool is given out to the staker from the block reward * @param stakerId The ID of the staker */ function giveBlockReward(uint32 epoch, uint32 stakerId) external; /** * @notice The function gives out penalties to stakers during commit. * The penalties are given for inactivity, failing to reveal * , deviation from the median value of particular asset * @param stakerId The staker id * @param epoch The Epoch value in consideration */ function giveInactivityPenalties(uint32 epoch, uint32 stakerId) external; }
contracts/randomNumber/IRandomNoProvider.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; interface IRandomNoProvider { /** * @notice Called by BlockManager in ClaimBlockReward or ConfirmBlockLastEpoch * @param epoch current epoch * @param _secret hash of encoded rando secret from stakers */ function provideSecret(uint32 epoch, bytes32 _secret) external; }
contracts/Initializable.sol
// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity ^0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * Forked from OZ's (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/b9125001f0a1c44d596ca3a47536f1a467e3a29d/contracts/proxy/utils/Initializable.sol) */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "contract already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } modifier initialized() { require(_initialized, "Contract should be initialized"); _; } }
@openzeppelin/contracts/utils/introspection/ERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
contracts/lib/Random.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; library Random { // pseudo random number generator based on hash. returns 0 -> max-1 // slither ignore reason : Internal library // slither-disable-next-line dead-code function prng(uint256 max, bytes32 randHash) internal pure returns (uint256) { uint256 sum = uint256(randHash); return (sum % max); } // pseudo random hash generator based on hashes. // slither ignore reason : Internal library // slither-disable-next-line dead-code function prngHash(bytes32 seed, bytes32 salt) internal pure returns (bytes32) { bytes32 prngHashVal = keccak256(abi.encodePacked(seed, salt)); return (prngHashVal); } }
contracts/Core/interface/IVoteManager.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../../lib/Structs.sol"; interface IVoteManager { /** * @notice stores the salt calculated in block manager * @param _salt the hash of the last epoch and medians of the block */ function storeSalt(bytes32 _salt) external; /** * @notice stores the depth of a valid merkle tree. Depth of the merkle tree sent by the stakers should match with this * for a valid commit/reveal * @param _depth depth of the merkle tree */ function storeDepth(uint256 _depth) external; /** * @notice returns vote value of a collection reported by a particular staker * @param epoch in which the staker reveal this value * @param stakerId id of the staker * @param leafId seq position of collection in merkle tree * @return vote value */ function getVoteValue( uint32 epoch, uint32 stakerId, uint16 leafId ) external view returns (uint256); /** * @notice returns vote weight of the value of the collection reported * @param epoch in which the staker reveal this value * @param leafId seq position of collection in merkle tree * @param voteValue one of the values of the collection being reported * @return vote weight of the vote */ function getVoteWeight( uint32 epoch, uint16 leafId, uint256 voteValue ) external view returns (uint256); /** * @notice returns snapshot of influence of the staker when they revealed * @param epoch when the snapshot was taken * @param stakerId id of the staker * @return influence of the staker */ function getInfluenceSnapshot(uint32 epoch, uint32 stakerId) external view returns (uint256); /** * @notice returns snapshot of stake of the staker when they revealed * @param epoch when the snapshot was taken * @param stakerId id of the staker * @return stake of the staker */ function getStakeSnapshot(uint32 epoch, uint32 stakerId) external view returns (uint256); /** * @notice returns the total influence revealed of the collection * @param epoch when asset was being revealed * @param leafId seq position of collection in merkle tree * @return total influence revealed of the collection */ function getTotalInfluenceRevealed(uint32 epoch, uint16 leafId) external view returns (uint256); /** * @notice returns the epoch a staker last revealed their votes * @param stakerId id of the staker * @return epoch last revealed */ function getEpochLastRevealed(uint32 stakerId) external view returns (uint32); /** * @notice returns the epoch a staker last committed their votes * @param stakerId id of the staker * @return epoch last committed */ function getEpochLastCommitted(uint32 stakerId) external view returns (uint32); /** * @return the salt */ function getSalt() external view returns (bytes32); }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
@openzeppelin/contracts/access/IAccessControl.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
contracts/Core/storage/Constants.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; contract Constants { enum State { Commit, Reveal, Propose, Dispute, Confirm, Buffer } enum StakeChanged { BlockReward, InactivityPenalty, Slashed } enum StakerRewardChanged { StakerRewardAdded, StakerRewardClaimed } enum AgeChanged { InactivityPenalty, VotingRewardOrPenalty } uint8 public constant NUM_STATES = 5; uint16 public constant EPOCH_LENGTH = 1200; // slither-disable-next-line too-many-digits address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD; uint32 public constant BASE_DENOMINATOR = 10_000_000; // keccak256("BLOCK_CONFIRMER_ROLE") bytes32 public constant BLOCK_CONFIRMER_ROLE = 0x18797bc7973e1dadee1895be2f1003818e30eae3b0e7a01eb9b2e66f3ea2771f; // keccak256("STAKE_MODIFIER_ROLE") bytes32 public constant STAKE_MODIFIER_ROLE = 0xdbaaaff2c3744aa215ebd99971829e1c1b728703a0bf252f96685d29011fc804; // keccak256("REWARD_MODIFIER_ROLE") bytes32 public constant REWARD_MODIFIER_ROLE = 0xcabcaf259dd9a27f23bd8a92bacd65983c2ebf027c853f89f941715905271a8d; // keccak256("COLLECTION_MODIFIER_ROLE") bytes32 public constant COLLECTION_MODIFIER_ROLE = 0xa3a75e7cd2b78fcc3ae2046ab93bfa4ac0b87ed7ea56646a312cbcb73eabd294; // keccak256("VOTE_MODIFIER_ROLE") bytes32 public constant VOTE_MODIFIER_ROLE = 0x912208965b92edeb3eb82a612c87b38b5e844f7539cb396f0d08ec012e511b07; // keccak256("DELEGATOR_MODIFIER_ROLE") bytes32 public constant DELEGATOR_MODIFIER_ROLE = 0x6b7da7a33355c6e035439beb2ac6a052f1558db73f08690b1c9ef5a4e8389597; // keccak256("REGISTRY_MODIFIER_ROLE") bytes32 public constant REGISTRY_MODIFIER_ROLE = 0xca51085219bef34771da292cb24ee4fcf0ae6bdba1a62c17d1fb7d58be802883; // keccak256("SECRETS_MODIFIER_ROLE") bytes32 public constant SECRETS_MODIFIER_ROLE = 0x46aaf8a125792dfff6db03d74f94fe1acaf55c8cab22f65297c15809c364465c; // keccak256("PAUSE_ROLE") bytes32 public constant PAUSE_ROLE = 0x139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d; // keccak256("GOVERNANCE_ROLE") bytes32 public constant GOVERNANCE_ROLE = 0x71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb1; // keccak256("STOKEN_ROLE") bytes32 public constant STOKEN_ROLE = 0xce3e6c780f179d7a08d28e380f7be9c36d990f56515174f8adb6287c543e30dc; // keccak256("SALT_MODIFIER_ROLE") bytes32 public constant SALT_MODIFIER_ROLE = 0xf31dda80d37c96a1a0852ace387dda52a75487d7d4eb74895e749ede3e0987b4; // keccak256("DEPTH_MODIFIER_ROLE)") bytes32 public constant DEPTH_MODIFIER_ROLE = 0x91f5d9ea80c4d04985e669bc72870410b28b57afdf61c0d50d377766d86a3748; // keccak256("ESCAPE_HATCH_ROLE") bytes32 public constant ESCAPE_HATCH_ROLE = 0x518d8c39717318f051dfb836a4ebe5b3c34aa2cb7fce26c21a89745422ba8043; }
contracts/Core/interface/IStakeManager.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "../../lib/Structs.sol"; import "../storage/Constants.sol"; interface IStakeManager { /** * @notice External function for setting stake of the staker * Used by RewardManager * @param _epoch The epoch in which stake changes * @param _id of the staker * @param reason the reason for stake to change * @param prevStake previous stake of the staker * @param _stake updated stake of the staker */ function setStakerStake( uint32 _epoch, uint32 _id, Constants.StakeChanged reason, uint256 prevStake, uint256 _stake ) external; /** * @notice The function is used by the Votemanager reveal function and BlockManager FinalizeDispute * to penalise the staker who lost his secret and make his stake less by "slashPenaltyAmount" and * transfer to bounty hunter half the "slashPenaltyAmount" of the staker * @param stakerId The ID of the staker who is penalised * @param bountyHunter The address of the bounty hunter */ function slash( uint32 epoch, uint32 stakerId, address bountyHunter ) external; /** * @notice External function for setting staker age of the staker * Used by RewardManager * @param _epoch The epoch in which age changes * @param _id of the staker * @param _age the updated new age * @param reason the reason for age change */ function setStakerAge( uint32 _epoch, uint32 _id, uint32 _age, Constants.AgeChanged reason ) external; /** * @notice External function for setting stakerReward of the staker * Used by RewardManager * @param _epoch The epoch in which stakerReward changes * @param _id of the staker * @param reason the reason for stakerReward to change * @param prevStakerReward previous stakerReward of the staker * @param _stakerReward updated stakerReward of the staker */ function setStakerReward( uint32 _epoch, uint32 _id, Constants.StakerRewardChanged reason, uint256 prevStakerReward, uint256 _stakerReward ) external; /** * @notice External function for setting epochLastPenalized of the staker * Used by RewardManager * @param _id of the staker */ function setStakerEpochFirstStakedOrLastPenalized(uint32 _epoch, uint32 _id) external; /** * @notice remove all funds in case of emergency */ function escape(address _address) external; /** * @notice event being thrown after every successful sRZR transfer taking place * @param from sender * @param to recepient * @param amount srzr amount being transferred * @param stakerId of the staker */ function srzrTransfer( address from, address to, uint256 amount, uint32 stakerId ) external; /** * @param _address Address of the staker * @return The staker ID */ function getStakerId(address _address) external view returns (uint32); /** * @param _id The staker ID * @return staker The Struct of staker information */ function getStaker(uint32 _id) external view returns (Structs.Staker memory staker); /** * @return The number of stakers in the razor network */ function getNumStakers() external view returns (uint32); /** * @return influence of staker */ function getInfluence(uint32 stakerId) external view returns (uint256); /** * @return stake of staker */ function getStake(uint32 stakerId) external view returns (uint256); /** * @return epochFirstStakedOrLastPenalized of staker */ function getEpochFirstStakedOrLastPenalized(uint32 stakerId) external view returns (uint32); /** * @return length of maturities array */ function maturitiesLength() external view returns (uint32); }
Contract ABI
[{"type":"event","name":"RandomNumberAvailable","inputs":[{"type":"uint32","name":"epoch","internalType":"uint32","indexed":false}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"previousAdminRole","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"newAdminRole","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"BASE_DENOMINATOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"BLOCK_CONFIRMER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"BURN_ADDRESS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"COLLECTION_MODIFIER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DELEGATOR_MODIFIER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEPTH_MODIFIER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"EPOCH_LENGTH","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"ESCAPE_HATCH_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"GOVERNANCE_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"NUM_STATES","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"PAUSE_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"REGISTRY_MODIFIER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"REWARD_MODIFIER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"SALT_MODIFIER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"SECRETS_MODIFIER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"STAKE_MODIFIER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"STOKEN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"VOTE_MODIFIER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"buffer","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getGenericRandomNumber","inputs":[{"type":"uint32","name":"epoch","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getGenericRandomNumberOfLastEpoch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRandomNumber","inputs":[{"type":"bytes32","name":"requestId","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"blockManagerAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"nonce","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"provideSecret","inputs":[{"type":"uint32","name":"epoch","internalType":"uint32"},{"type":"bytes32","name":"_secret","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes32","name":"requestId","internalType":"bytes32"}],"name":"register","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"requests","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"secrets","inputs":[{"type":"uint32","name":"","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBufferLength","inputs":[{"type":"uint8","name":"_bufferLength","internalType":"uint8"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]}]
Contract Creation Code
0x60806040526005805460ff19168117905534801561001c57600080fd5b5061002860003361002d565b6100c2565b610037828261003b565b5050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff166100375760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6114d7806100d16000396000f3fe608060405234801561001057600080fd5b506004361061025c5760003560e01c80639ea7ec5311610145578063da984295116100bd578063eeef792b1161008c578063f36c8f5c11610071578063f36c8f5c14610669578063fccc281314610690578063ffe87625146106be57600080fd5b8063eeef792b14610622578063ef8bf6841461064257600080fd5b8063da984295146105b4578063db7b4996146105db578063ed6c935d146105ee578063edaafe201461061557600080fd5b8063bd85958411610114578063c4d66de8116100f9578063c4d66de81461057b578063cb923ccd1461058e578063d547741f146105a157600080fd5b8063bd85958414610569578063c3b6f51b1461057357600080fd5b80639ea7ec531461050b578063a217fddf1461051e578063ac4746ab14610526578063b0daafef1461054257600080fd5b806341d296f7116101d857806370ae92d2116101a7578063885fc0941161018c578063885fc0941461047857806391d148541461049f5780639d866985146104e557600080fd5b806370ae92d214610416578063776076e71461045157600080fd5b806341d296f71461037a5780634912b72a146103a15780635b070278146103c8578063622f9330146103ef57600080fd5b80632d93b9a01161022f5780632f50bcc4116102145780632f50bcc41461031957806336568abe14610340578063389ed2671461035357600080fd5b80632d93b9a0146102dd5780632f2ff15d1461030457600080fd5b806301ffc9a71461026157806305db56df146102895780631aa3a008146102a3578063248a9ca3146102b9575b600080fd5b61027461026f366004611239565b6106d1565b60405190151581526020015b60405180910390f35b610291600581565b60405160ff9091168152602001610280565b6102ab61076a565b604051908152602001610280565b6102ab6102c73660046111f6565b6000908152600160208190526040909120015490565b6102ab7f912208965b92edeb3eb82a612c87b38b5e844f7539cb396f0d08ec012e511b0781565b61031761031236600461120e565b6108c2565b005b6102ab7f46aaf8a125792dfff6db03d74f94fe1acaf55c8cab22f65297c15809c364465c81565b61031761034e36600461120e565b6108ed565b6102ab7f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d81565b6102ab7f91f5d9ea80c4d04985e669bc72870410b28b57afdf61c0d50d377766d86a374881565b6102ab7f6b7da7a33355c6e035439beb2ac6a052f1558db73f08690b1c9ef5a4e838959781565b6102ab7fce3e6c780f179d7a08d28e380f7be9c36d990f56515174f8adb6287c543e30dc81565b6102ab7f518d8c39717318f051dfb836a4ebe5b3c34aa2cb7fce26c21a89745422ba804381565b61043c6104243660046111dc565b60026020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610280565b6102ab7fdbaaaff2c3744aa215ebd99971829e1c1b728703a0bf252f96685d29011fc80481565b6102ab7fa3a75e7cd2b78fcc3ae2046ab93bfa4ac0b87ed7ea56646a312cbcb73eabd29481565b6102746104ad36600461120e565b600091825260016020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b61043c6104f33660046111f6565b60036020526000908152604090205463ffffffff1681565b6102ab610519366004611279565b610986565b6102ab600081565b61052f6104b081565b60405161ffff9091168152602001610280565b6102ab7ff31dda80d37c96a1a0852ace387dda52a75487d7d4eb74895e749ede3e0987b481565b61043c6298968081565b6102ab610992565b6103176105893660046111dc565b6109ba565b6102ab61059c3660046111f6565b610ac6565b6103176105af36600461120e565b610aec565b6102ab7f18797bc7973e1dadee1895be2f1003818e30eae3b0e7a01eb9b2e66f3ea2771f81565b6103176105e93660046112bc565b610b12565b6102ab7fca51085219bef34771da292cb24ee4fcf0ae6bdba1a62c17d1fb7d58be80288381565b6005546102919060ff1681565b6102ab610630366004611279565b60046020526000908152604090205481565b6102ab7fcabcaf259dd9a27f23bd8a92bacd65983c2ebf027c853f89f941715905271a8d81565b6102ab7f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb181565b61069961dead81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610280565b6103176106cc366004611293565b610b53565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061076457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000805460ff166107c25760405162461bcd60e51b815260206004820152601e60248201527f436f6e74726163742073686f756c6420626520696e697469616c697a6564000060448201526064015b60405180910390fd5b60006107cc610c83565b336000908152600260205260409020549091506107f09063ffffffff1660016113a9565b33600081815260026020908152604091829020805463ffffffff861663ffffffff19909116179055905160e09390931b7fffffffff00000000000000000000000000000000000000000000000000000000169083015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602482015260380160405160208183030381529060405280519060200120915080600161089891906113a9565b6000838152600360205260409020805463ffffffff191663ffffffff929092169190911790555090565b600082815260016020819052604090912001546108de81610c96565b6108e88383610ca3565b505050565b73ffffffffffffffffffffffffffffffffffffffff811633146109785760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084016107b9565b6109828282610d44565b5050565b60006107648282610de1565b60008061099d610c83565b90506109b46109ad60018361141f565b6000610de1565b91505090565b600054610100900460ff16806109d3575060005460ff16155b610a1f5760405162461bcd60e51b815260206004820152601c60248201527f636f6e747261637420616c726561647920696e697469616c697a65640000000060448201526064016107b9565b600054610100900460ff16158015610a5e57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b6000610a6981610c96565b610a937f46aaf8a125792dfff6db03d74f94fe1acaf55c8cab22f65297c15809c364465c846108c2565b50801561098257600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555050565b60008181526003602052604081205463ffffffff16610ae58184610de1565b9392505050565b60008281526001602081905260409091200154610b0881610c96565b6108e88383610d44565b7f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb1610b3c81610c96565b506005805460ff191660ff92909216919091179055565b60005460ff16610ba55760405162461bcd60e51b815260206004820152601e60248201527f436f6e74726163742073686f756c6420626520696e697469616c697a6564000060448201526064016107b9565b7f46aaf8a125792dfff6db03d74f94fe1acaf55c8cab22f65297c15809c364465c610bcf81610c96565b63ffffffff831660009081526004602052604090205415610c325760405162461bcd60e51b815260206004820152601260248201527f53656372657420616c726561647920736574000000000000000000000000000060448201526064016107b9565b63ffffffff831660008181526004602090815260409182902085905590519182527ff32abc205bbcb77c248566ea3ab28cff264d2dadb9e197795fae6ac4574ccc5e910160405180910390a1505050565b6000610c916104b0426113d1565b905090565b610ca08133610e57565b50565b600082815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661098257600082815260016020818152604080842073ffffffffffffffffffffffffffffffffffffffff86168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b600082815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff161561098257600082815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b63ffffffff821660009081526004602052604081205480610e445760405162461bcd60e51b815260206004820152601f60248201527f52616e646f6d204e756d626572206e6f742067656e617261746564207965740060448201526064016107b9565b610e4e8184610ef1565b91506107649050565b600082815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661098257610eaf8173ffffffffffffffffffffffffffffffffffffffff166014610f30565b610eba836020610f30565b604051602001610ecb9291906112dd565b60408051601f198184030181529082905262461bcd60e51b82526107b99160040161135e565b6000808383604051602001610f10929190918252602082015260400190565b60408051808303601f190181529190528051602090910120949350505050565b60606000610f3f836002611400565b610f4a906002611391565b67ffffffffffffffff811115610f7057634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015610f9a576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110610fdf57634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061105057634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600061108c846002611400565b611097906001611391565b90505b6001811115611150577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106110e657634e487b7160e01b600052603260045260246000fd5b1a60f81b82828151811061110a57634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361114981611474565b905061109a565b508315610ae55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016107b9565b803573ffffffffffffffffffffffffffffffffffffffff811681146111c357600080fd5b919050565b803563ffffffff811681146111c357600080fd5b6000602082840312156111ed578081fd5b610ae58261119f565b600060208284031215611207578081fd5b5035919050565b60008060408385031215611220578081fd5b823591506112306020840161119f565b90509250929050565b60006020828403121561124a578081fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610ae5578182fd5b60006020828403121561128a578081fd5b610ae5826111c8565b600080604083850312156112a5578182fd5b6112ae836111c8565b946020939093013593505050565b6000602082840312156112cd578081fd5b813560ff81168114610ae5578182fd5b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611315816017850160208801611444565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351611352816028840160208801611444565b01602801949350505050565b602081526000825180602084015261137d816040850160208701611444565b601f01601f19169190910160400192915050565b600082198211156113a4576113a461148b565b500190565b600063ffffffff8083168185168083038211156113c8576113c861148b565b01949350505050565b600063ffffffff808416806113f457634e487b7160e01b83526012600452602483fd5b92169190910492915050565b600081600019048311821515161561141a5761141a61148b565b500290565b600063ffffffff8381169083168181101561143c5761143c61148b565b039392505050565b60005b8381101561145f578181015183820152602001611447565b8381111561146e576000848401525b50505050565b6000816114835761148361148b565b506000190190565b634e487b7160e01b600052601160045260246000fdfea26469706673582212206fb196d5cf096a73cdfb5ba3bcf7e7682359b7efe62caf31a2448feeb20b81ff64736f6c63430008040033
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061025c5760003560e01c80639ea7ec5311610145578063da984295116100bd578063eeef792b1161008c578063f36c8f5c11610071578063f36c8f5c14610669578063fccc281314610690578063ffe87625146106be57600080fd5b8063eeef792b14610622578063ef8bf6841461064257600080fd5b8063da984295146105b4578063db7b4996146105db578063ed6c935d146105ee578063edaafe201461061557600080fd5b8063bd85958411610114578063c4d66de8116100f9578063c4d66de81461057b578063cb923ccd1461058e578063d547741f146105a157600080fd5b8063bd85958414610569578063c3b6f51b1461057357600080fd5b80639ea7ec531461050b578063a217fddf1461051e578063ac4746ab14610526578063b0daafef1461054257600080fd5b806341d296f7116101d857806370ae92d2116101a7578063885fc0941161018c578063885fc0941461047857806391d148541461049f5780639d866985146104e557600080fd5b806370ae92d214610416578063776076e71461045157600080fd5b806341d296f71461037a5780634912b72a146103a15780635b070278146103c8578063622f9330146103ef57600080fd5b80632d93b9a01161022f5780632f50bcc4116102145780632f50bcc41461031957806336568abe14610340578063389ed2671461035357600080fd5b80632d93b9a0146102dd5780632f2ff15d1461030457600080fd5b806301ffc9a71461026157806305db56df146102895780631aa3a008146102a3578063248a9ca3146102b9575b600080fd5b61027461026f366004611239565b6106d1565b60405190151581526020015b60405180910390f35b610291600581565b60405160ff9091168152602001610280565b6102ab61076a565b604051908152602001610280565b6102ab6102c73660046111f6565b6000908152600160208190526040909120015490565b6102ab7f912208965b92edeb3eb82a612c87b38b5e844f7539cb396f0d08ec012e511b0781565b61031761031236600461120e565b6108c2565b005b6102ab7f46aaf8a125792dfff6db03d74f94fe1acaf55c8cab22f65297c15809c364465c81565b61031761034e36600461120e565b6108ed565b6102ab7f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d81565b6102ab7f91f5d9ea80c4d04985e669bc72870410b28b57afdf61c0d50d377766d86a374881565b6102ab7f6b7da7a33355c6e035439beb2ac6a052f1558db73f08690b1c9ef5a4e838959781565b6102ab7fce3e6c780f179d7a08d28e380f7be9c36d990f56515174f8adb6287c543e30dc81565b6102ab7f518d8c39717318f051dfb836a4ebe5b3c34aa2cb7fce26c21a89745422ba804381565b61043c6104243660046111dc565b60026020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610280565b6102ab7fdbaaaff2c3744aa215ebd99971829e1c1b728703a0bf252f96685d29011fc80481565b6102ab7fa3a75e7cd2b78fcc3ae2046ab93bfa4ac0b87ed7ea56646a312cbcb73eabd29481565b6102746104ad36600461120e565b600091825260016020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b61043c6104f33660046111f6565b60036020526000908152604090205463ffffffff1681565b6102ab610519366004611279565b610986565b6102ab600081565b61052f6104b081565b60405161ffff9091168152602001610280565b6102ab7ff31dda80d37c96a1a0852ace387dda52a75487d7d4eb74895e749ede3e0987b481565b61043c6298968081565b6102ab610992565b6103176105893660046111dc565b6109ba565b6102ab61059c3660046111f6565b610ac6565b6103176105af36600461120e565b610aec565b6102ab7f18797bc7973e1dadee1895be2f1003818e30eae3b0e7a01eb9b2e66f3ea2771f81565b6103176105e93660046112bc565b610b12565b6102ab7fca51085219bef34771da292cb24ee4fcf0ae6bdba1a62c17d1fb7d58be80288381565b6005546102919060ff1681565b6102ab610630366004611279565b60046020526000908152604090205481565b6102ab7fcabcaf259dd9a27f23bd8a92bacd65983c2ebf027c853f89f941715905271a8d81565b6102ab7f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb181565b61069961dead81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610280565b6103176106cc366004611293565b610b53565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061076457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000805460ff166107c25760405162461bcd60e51b815260206004820152601e60248201527f436f6e74726163742073686f756c6420626520696e697469616c697a6564000060448201526064015b60405180910390fd5b60006107cc610c83565b336000908152600260205260409020549091506107f09063ffffffff1660016113a9565b33600081815260026020908152604091829020805463ffffffff861663ffffffff19909116179055905160e09390931b7fffffffff00000000000000000000000000000000000000000000000000000000169083015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602482015260380160405160208183030381529060405280519060200120915080600161089891906113a9565b6000838152600360205260409020805463ffffffff191663ffffffff929092169190911790555090565b600082815260016020819052604090912001546108de81610c96565b6108e88383610ca3565b505050565b73ffffffffffffffffffffffffffffffffffffffff811633146109785760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084016107b9565b6109828282610d44565b5050565b60006107648282610de1565b60008061099d610c83565b90506109b46109ad60018361141f565b6000610de1565b91505090565b600054610100900460ff16806109d3575060005460ff16155b610a1f5760405162461bcd60e51b815260206004820152601c60248201527f636f6e747261637420616c726561647920696e697469616c697a65640000000060448201526064016107b9565b600054610100900460ff16158015610a5e57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b6000610a6981610c96565b610a937f46aaf8a125792dfff6db03d74f94fe1acaf55c8cab22f65297c15809c364465c846108c2565b50801561098257600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555050565b60008181526003602052604081205463ffffffff16610ae58184610de1565b9392505050565b60008281526001602081905260409091200154610b0881610c96565b6108e88383610d44565b7f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb1610b3c81610c96565b506005805460ff191660ff92909216919091179055565b60005460ff16610ba55760405162461bcd60e51b815260206004820152601e60248201527f436f6e74726163742073686f756c6420626520696e697469616c697a6564000060448201526064016107b9565b7f46aaf8a125792dfff6db03d74f94fe1acaf55c8cab22f65297c15809c364465c610bcf81610c96565b63ffffffff831660009081526004602052604090205415610c325760405162461bcd60e51b815260206004820152601260248201527f53656372657420616c726561647920736574000000000000000000000000000060448201526064016107b9565b63ffffffff831660008181526004602090815260409182902085905590519182527ff32abc205bbcb77c248566ea3ab28cff264d2dadb9e197795fae6ac4574ccc5e910160405180910390a1505050565b6000610c916104b0426113d1565b905090565b610ca08133610e57565b50565b600082815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661098257600082815260016020818152604080842073ffffffffffffffffffffffffffffffffffffffff86168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b600082815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff161561098257600082815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b63ffffffff821660009081526004602052604081205480610e445760405162461bcd60e51b815260206004820152601f60248201527f52616e646f6d204e756d626572206e6f742067656e617261746564207965740060448201526064016107b9565b610e4e8184610ef1565b91506107649050565b600082815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661098257610eaf8173ffffffffffffffffffffffffffffffffffffffff166014610f30565b610eba836020610f30565b604051602001610ecb9291906112dd565b60408051601f198184030181529082905262461bcd60e51b82526107b99160040161135e565b6000808383604051602001610f10929190918252602082015260400190565b60408051808303601f190181529190528051602090910120949350505050565b60606000610f3f836002611400565b610f4a906002611391565b67ffffffffffffffff811115610f7057634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015610f9a576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110610fdf57634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061105057634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600061108c846002611400565b611097906001611391565b90505b6001811115611150577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106110e657634e487b7160e01b600052603260045260246000fd5b1a60f81b82828151811061110a57634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361114981611474565b905061109a565b508315610ae55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016107b9565b803573ffffffffffffffffffffffffffffffffffffffff811681146111c357600080fd5b919050565b803563ffffffff811681146111c357600080fd5b6000602082840312156111ed578081fd5b610ae58261119f565b600060208284031215611207578081fd5b5035919050565b60008060408385031215611220578081fd5b823591506112306020840161119f565b90509250929050565b60006020828403121561124a578081fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610ae5578182fd5b60006020828403121561128a578081fd5b610ae5826111c8565b600080604083850312156112a5578182fd5b6112ae836111c8565b946020939093013593505050565b6000602082840312156112cd578081fd5b813560ff81168114610ae5578182fd5b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611315816017850160208801611444565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351611352816028840160208801611444565b01602801949350505050565b602081526000825180602084015261137d816040850160208701611444565b601f01601f19169190910160400192915050565b600082198211156113a4576113a461148b565b500190565b600063ffffffff8083168185168083038211156113c8576113c861148b565b01949350505050565b600063ffffffff808416806113f457634e487b7160e01b83526012600452602483fd5b92169190910492915050565b600081600019048311821515161561141a5761141a61148b565b500290565b600063ffffffff8381169083168181101561143c5761143c61148b565b039392505050565b60005b8381101561145f578181015183820152602001611447565b8381111561146e576000848401525b50505050565b6000816114835761148361148b565b506000190190565b634e487b7160e01b600052601160045260246000fdfea26469706673582212206fb196d5cf096a73cdfb5ba3bcf7e7682359b7efe62caf31a2448feeb20b81ff64736f6c63430008040033