diff --git a/README.md b/README.md index d07e05f..ed212c8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Vornoi · [![GitHub license](https://img.shields.io/badge/license-GPL3%2FApache2-blue)](https://github.com/Qrucial/voronoi/blob/main/LICENSE) Making "decentralized" blockchain projects actually decentralized. Currently implementing the solutions: for Polkadot and Ethereum. +The currently deployable Voronoi code can be smart contract folder. Voronoi ERC20 implementation is already in beta version. ### Assumption Cryptocurrency project with decentralization as one of the core principle. @@ -37,6 +38,11 @@ Always publish the address on multiple public sources so users can verify it bef ### Example Topology of a real decentralized smart contract ![Decentralized Organization](/images/DecentraLibExample.jpg) + +### Voronoi on Moonbase Alpha testnet +Explorer URL: https://moonbase-blockscout.testnet.moonbeam.network/tx/0xb43184f219f3e32607ecf0527787d64c25c42ec46b407bcce6d4606ef861e7f9 + + ### Contributing Voronoi is an open project which welcomes contribution. Please send us a pull request in case you have a contribution. diff --git a/smart_contracts/voronoi_ERC20.sol b/smart_contracts/voronoi_ERC20.sol new file mode 100644 index 0000000..cff89a9 --- /dev/null +++ b/smart_contracts/voronoi_ERC20.sol @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: Apache-2.0 +// Example of Voronoi Solidity solution, by QRUCIAL OÜ +// Code state: Beta +// Coder: Six + +pragma solidity ^0.8.11; + +contract VoronoiToken { + string public constant name = "VoronoiERC20"; + string public constant symbol = "VE2"; + uint8 public constant decimals = 0; + + event Transfer(address indexed _from, address indexed _to, uint256 _value); + event Approval(address indexed _owner, address indexed _spender, uint256 _value); + event major_impact_call(bool value); // Event when a Major Impact Function is called + event minor_impact_call(bool value); // Event when a Minor Impact Function is called + event function_unlock(uint256 value); // Unlock event, when a function gets unlocked, unit256 -> func ID + + mapping(address => uint256) balances; + mapping(address => mapping (address => uint256)) allowed; + + mapping (uint256 => address) internal unlocker_ids; // Needs to be in sync with the unlocker_ids, max 10 + mapping (uint256 => uint256) internal unlocker_stakes; // Address to threshold amount (single account can have multiple) + + uint256 private totalSupply_ = 100000000; + address private admin; + uint256 private _voronoi_count; + uint256 private threshold; + uint256 private _voronoi_last_time; + + bool private _paused; + + constructor() { + admin = msg.sender; + balances[msg.sender] = totalSupply_; + _paused = false; + _voronoi_count = 0; + threshold = 3; + _voronoi_last_time = block.timestamp; + unlocker_ids[0] = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4; + unlocker_ids[1] = 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2; + unlocker_ids[2] = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c; + unlocker_ids[3] = 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db; + unlocker_ids[4] = 0x617F2E2fD72FD9D5503197092aC168c91465E7f2; + unlocker_ids[5] = 0x1aE0EA34a72D944a8C7603FfB3eC30a6669E454C; + unlocker_ids[6] = 0x583031D1113aD414F02576BD6afaBfb302140225; + unlocker_ids[7] = 0x583031D1113aD414F02576BD6afaBfb302140225; + unlocker_ids[8] = 0x0A098Eda01Ce92ff4A4CCb7A4fFFb5A43EBC70DC; + unlocker_ids[9] = 0x0A098Eda01Ce92ff4A4CCb7A4fFFb5A43EBC70DC; + unlocker_stakes[0] = 1; + unlocker_stakes[1] = 1; + unlocker_stakes[2] = 1; + unlocker_stakes[3] = 1; + unlocker_stakes[4] = 1; + unlocker_stakes[5] = 1; + unlocker_stakes[6] = 1; + unlocker_stakes[7] = 1; + unlocker_stakes[8] = 1; + unlocker_stakes[9] = 1; + } + + function voronoi_stake_up() external returns (bool success){ + emit minor_impact_call(true); + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + + if (msg.sender == unlocker_ids[0]){ + require(unlocker_stakes[0] == 1); + unlocker_stakes[0] = 0; + } + else if (msg.sender == unlocker_ids[1]) { + require(unlocker_stakes[1] == 1); + unlocker_stakes[1] = 0; + } + else if (msg.sender == unlocker_ids[2]) { + require(unlocker_stakes[2] == 1); + unlocker_stakes[2] = 0; + } + else if (msg.sender == unlocker_ids[3]) { + require(unlocker_stakes[3] == 1); + unlocker_stakes[3] = 0; + } + else if (msg.sender == unlocker_ids[4]) { + require(unlocker_stakes[4] == 1); + unlocker_stakes[4] = 0; + } + else if (msg.sender == unlocker_ids[5]) { + require(unlocker_stakes[5] == 1); + unlocker_stakes[5] = 0; + } + else if (msg.sender == unlocker_ids[6]) { + require(unlocker_stakes[6] == 1); + unlocker_stakes[6] = 0; + } + else if (msg.sender == unlocker_ids[7]) { + require(unlocker_stakes[7] == 1); + unlocker_stakes[7] = 0; + } + else if (msg.sender == unlocker_ids[8]) { + require(unlocker_stakes[8] == 1); + unlocker_stakes[8] = 0; + } + else if (msg.sender == unlocker_ids[9]) { + require(unlocker_stakes[9] == 1); + unlocker_stakes[9] = 0; + } + _voronoi_count = _voronoi_count + 1; + return true; + } + + function vcheck_stake(uint256 _idToCheck) external view returns(uint256 success){ + return unlocker_stakes[_idToCheck]; + } + + function vcheck_count() external view returns(uint256 success){ + return _voronoi_count; + } + + function v_reset() external returns (bool success){ + emit major_impact_call(true); + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + require(block.timestamp >= _voronoi_last_time + 1 minutes); // You can only do it once every hour to secure voting logic + _voronoi_last_time = block.timestamp; + _voronoi_count = 0; + unlocker_stakes[0] = 1; + unlocker_stakes[1] = 1; + unlocker_stakes[2] = 1; + unlocker_stakes[3] = 1; + unlocker_stakes[4] = 1; + unlocker_stakes[5] = 1; + unlocker_stakes[6] = 1; + unlocker_stakes[7] = 1; + unlocker_stakes[8] = 1; + unlocker_stakes[9] = 1; + return true; + } + + function unlocker_role_change(uint256 _id, address _new_unlocker) external returns (bool){ + emit major_impact_call(true); + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + require(_voronoi_count >= threshold); + unlocker_ids[_id] = _new_unlocker; + return true; + } + + + function pause() external returns (bool success) { + emit major_impact_call(true); + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + emit major_impact_call(true); + require(_voronoi_count >= threshold); + _paused = true; + return _paused; + } + + function unpause() external returns (bool success) { + emit major_impact_call(true); + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + emit major_impact_call(true); + require(_voronoi_count >= threshold); + _paused = false; + return _paused; + } + + function adminChange(address newAdmin) external returns (address to) { + emit major_impact_call(true); + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + emit major_impact_call(true); + require(_voronoi_count >= threshold); + require(address(newAdmin) != address(0)); + admin = newAdmin; + return newAdmin; + } + + + function totalSupply() external view returns (uint256) { + return totalSupply_; + } + + function balanceOf(address _owner) external view returns (uint256 balance) { + return balances[_owner]; + } + + function transfer(address _to, uint256 _value) external returns (bool success) { + emit minor_impact_call(true); + require(_paused == false); + require(_value <= balances[msg.sender]); + balances[msg.sender] -= _value; + balances[_to] += _value; + emit Transfer(msg.sender, _to, _value); + return true; + } + + function transferFrom(address _from, address _to, uint256 _value) external returns (bool success) { + emit minor_impact_call(true); + require(_paused == false); + require(_value <= balances[_from]); + require(_value <= allowed[_from][msg.sender]); + balances[_from] -= _value; + allowed[_from][msg.sender] -= _value; + balances[_to] += _value; + emit Transfer(_from, _to, _value); + return true; + } + + function approve(address _spender, uint256 _value) external returns (bool success) { + emit minor_impact_call(true); + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + + function allowance(address _owner, address _spender) external view returns (uint remaining) { + return allowed[_owner][_spender]; + } + + function adminWithdraw() external returns (bool success) { + emit major_impact_call(true); + require(msg.sender == admin, "Not authorized"); + require(_voronoi_count >= threshold); + payable(msg.sender).transfer(address(this).balance); + return true; + } + + fallback() external payable {} + receive() external payable {} +} diff --git a/smart_contracts/voronoi_dao.sol b/smart_contracts/voronoi_dao.sol new file mode 100644 index 0000000..a5659bf --- /dev/null +++ b/smart_contracts/voronoi_dao.sol @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: Apache-2.0 +// Example of Voronoi DAO in Solidity, by QRUCIAL OÜ +// Setup: One leader (could be CEO, Prime Minister, etc irl) and 10 voters (could be members of the board, etc). +// Code state: Beta +// Coder: Six + +pragma solidity ^0.8.11; + +contract VoronoiDAO { + + event Transfer(address indexed _from, address indexed _to, uint256 _value); + event Approval(address indexed _owner, address indexed _spender, uint256 _value); + event major_impact_call(bool value); // Event when a Major Impact Function is called + event minor_impact_call(bool value); // Event when a Minor Impact Function is called + event function_unlock(uint256 value); // Unlock event, when a function gets unlocked, unit256 -> func ID + + mapping (uint256 => address) internal unlocker_ids; // Needs to be in sync with the unlocker_ids, max 10 + mapping (uint256 => uint256) internal unlocker_stakes; // Address to threshold amount (single account can have multiple) + mapping (uint256 => uint256) internal voronoi_function_count; // Some functions need to be controlled separately + mapping (uint256 => address) internal nominee; // Possibilty to nominate. To get in, vouches are needed. + mapping (uint256 => uint256) internal nominee_vouch; + uint256 private nominee_position; + + address private Leader; + uint256 private _voronoi_count; + uint256 private threshold; + uint256 private _voronoi_last_time; + + bool private _paused; + + constructor() { + Leader = msg.sender; // The Leader is the one who starts the DAO! Can be modified by voting. + _paused = false; + _voronoi_count = 0; + threshold = 4; + _voronoi_last_time = block.timestamp; + unlocker_ids[0] = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4; + unlocker_ids[1] = 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2; + unlocker_ids[2] = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c; + unlocker_ids[3] = 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db; + unlocker_ids[4] = 0x617F2E2fD72FD9D5503197092aC168c91465E7f2; + unlocker_ids[5] = 0x1aE0EA34a72D944a8C7603FfB3eC30a6669E454C; + unlocker_ids[6] = 0x583031D1113aD414F02576BD6afaBfb302140225; + unlocker_ids[7] = 0x583031D1113aD414F02576BD6afaBfb302140225; + unlocker_ids[8] = 0x0A098Eda01Ce92ff4A4CCb7A4fFFb5A43EBC70DC; + unlocker_ids[9] = 0x0A098Eda01Ce92ff4A4CCb7A4fFFb5A43EBC70DC; + unlocker_stakes[0] = 1; + unlocker_stakes[1] = 1; + unlocker_stakes[2] = 1; + unlocker_stakes[3] = 1; + unlocker_stakes[4] = 1; + unlocker_stakes[5] = 1; + unlocker_stakes[6] = 1; + unlocker_stakes[7] = 1; + unlocker_stakes[8] = 1; + unlocker_stakes[9] = 1; + voronoi_function_count[0] = 0; + voronoi_function_count[1] = 0; + } + + function voronoi_vote_up_main() external returns (bool success){ + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + + if (msg.sender == unlocker_ids[0]){ + require(unlocker_stakes[0] == 1); + unlocker_stakes[0] = 0; + } + else if (msg.sender == unlocker_ids[1]) { + require(unlocker_stakes[1] == 1); + unlocker_stakes[1] = 0; + } + else if (msg.sender == unlocker_ids[2]) { + require(unlocker_stakes[2] == 1); + unlocker_stakes[2] = 0; + } + else if (msg.sender == unlocker_ids[3]) { + require(unlocker_stakes[3] == 1); + unlocker_stakes[3] = 0; + } + else if (msg.sender == unlocker_ids[4]) { + require(unlocker_stakes[4] == 1); + unlocker_stakes[4] = 0; + } + else if (msg.sender == unlocker_ids[5]) { + require(unlocker_stakes[5] == 1); + unlocker_stakes[5] = 0; + } + else if (msg.sender == unlocker_ids[6]) { + require(unlocker_stakes[6] == 1); + unlocker_stakes[6] = 0; + } + else if (msg.sender == unlocker_ids[7]) { + require(unlocker_stakes[7] == 1); + unlocker_stakes[7] = 0; + } + else if (msg.sender == unlocker_ids[8]) { + require(unlocker_stakes[8] == 1); + unlocker_stakes[8] = 0; + } + else if (msg.sender == unlocker_ids[9]) { + require(unlocker_stakes[9] == 1); + unlocker_stakes[9] = 0; + } + _voronoi_count = _voronoi_count + 1; + return true; + } + + function voronoi_vote_up_specific(uint256 _spec) external returns (bool success){ + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + + if (msg.sender == unlocker_ids[0]){ + require(unlocker_stakes[0] == 1); + unlocker_stakes[0] = 0; + } + else if (msg.sender == unlocker_ids[1]) { + require(unlocker_stakes[1] == 1); + unlocker_stakes[1] = 0; + } + else if (msg.sender == unlocker_ids[2]) { + require(unlocker_stakes[2] == 1); + unlocker_stakes[2] = 0; + } + else if (msg.sender == unlocker_ids[3]) { + require(unlocker_stakes[3] == 1); + unlocker_stakes[3] = 0; + } + else if (msg.sender == unlocker_ids[4]) { + require(unlocker_stakes[4] == 1); + unlocker_stakes[4] = 0; + } + else if (msg.sender == unlocker_ids[5]) { + require(unlocker_stakes[5] == 1); + unlocker_stakes[5] = 0; + } + else if (msg.sender == unlocker_ids[6]) { + require(unlocker_stakes[6] == 1); + unlocker_stakes[6] = 0; + } + else if (msg.sender == unlocker_ids[7]) { + require(unlocker_stakes[7] == 1); + unlocker_stakes[7] = 0; + } + else if (msg.sender == unlocker_ids[8]) { + require(unlocker_stakes[8] == 1); + unlocker_stakes[8] = 0; + } + else if (msg.sender == unlocker_ids[9]) { + require(unlocker_stakes[9] == 1); + unlocker_stakes[9] = 0; + } + voronoi_function_count[_spec] = voronoi_function_count[_spec] + 1; + return true; + } + + function vcheck_state(uint256 _idToCheck) external view returns(uint256 success){ + return unlocker_stakes[_idToCheck]; + } + + function vcheck_count() external view returns(uint256 success){ + return _voronoi_count; + } + + function v_reset() external returns (bool success){ + emit major_impact_call(true); + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + require(block.timestamp >= _voronoi_last_time + 15 minutes); // You can only do it once every 15 mins to secure voting logic + _voronoi_last_time = block.timestamp; + _voronoi_count = 0; + voronoi_function_count[0] = 0; + voronoi_function_count[1] = 0; + unlocker_stakes[0] = 1; + unlocker_stakes[1] = 1; + unlocker_stakes[2] = 1; + unlocker_stakes[3] = 1; + unlocker_stakes[4] = 1; + unlocker_stakes[5] = 1; + unlocker_stakes[6] = 1; + unlocker_stakes[7] = 1; + unlocker_stakes[8] = 1; + unlocker_stakes[9] = 1; + nominee[0] = address(0); + nominee_vouch[0] = 0; + return true; + } + + function voter_nominate(uint256 _position, address _new_addr) external returns (bool){ + require(block.timestamp >= _voronoi_last_time + 15 minutes); // Nomination can happen only once per 15 mins. + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + nominee[0] = _new_addr; + nominee_position = _position; + return true; + } + + function voter_role_change() external returns (bool){ // Change or remove addresses. + emit major_impact_call(true); + require(voronoi_function_count[0] >= threshold); // Needs to be specifically allowed! + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + unlocker_ids[nominee_position] = nominee[0]; + return true; + } + + + function pause() external returns (bool success) { + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + emit major_impact_call(true); + require(_voronoi_count >= threshold); + _paused = true; + return _paused; + } + + function unpause() external returns (bool success) { + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + emit major_impact_call(true); + require(_voronoi_count >= threshold); + _paused = false; + return _paused; + } + + function LeaderChange(address newLeader) external returns (address to) { + require(msg.sender == unlocker_ids[0] || + msg.sender == unlocker_ids[1] || + msg.sender == unlocker_ids[2] || + msg.sender == unlocker_ids[3] || + msg.sender == unlocker_ids[4] || + msg.sender == unlocker_ids[5] || + msg.sender == unlocker_ids[6] || + msg.sender == unlocker_ids[7] || + msg.sender == unlocker_ids[8] || + msg.sender == unlocker_ids[9]); + emit major_impact_call(true); + require(_voronoi_count >= threshold); + Leader = newLeader; + return newLeader; + } + + + function LeaderWithdraw() external returns (bool success) { // If the DAO decides, the Leader can withdraw all Coins. + require(msg.sender == Leader, "Not authorized"); + emit major_impact_call(true); + require(voronoi_function_count[1] >= threshold); // Needs to be specifically allowed! + payable(msg.sender).transfer(address(this).balance); + return true; + } + + fallback() external payable {} + receive() external payable {} +} diff --git a/smart_contracts/voronoi_solidity_example.sol b/smart_contracts/voronoi_solidity_example.sol deleted file mode 100644 index 1063521..0000000 --- a/smart_contracts/voronoi_solidity_example.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Example of Voronoi Solidity solution, by QRUCIAL OÜ -// Coder: Six -pragma solidity ^0.8.10; - -// DRAFT In this example, 4 parties (threshold = 4) out of 6 need to agree to execute the critical_impact() function -// Requirement: no single account should be able to call any Major Impact function. - -contract Voronoi_Example { - - mapping (address => uint256) internal unlockers; // Address to threshold amount (single account can have multiple) - mapping (uint256 => uint256) internal function_locks; // Function required to be unlocked - uint256 private threshold; // Threshold for unlock - - event major_impact_call(bool value); // Event when a Major Impact Function is called - event minor_impact_call(bool value); // Event when a Minor Impact Function is called - event function_unlock(uint256 value); // Unlock event, when a function gets unlocked, unit256 -> func ID - - constructor() { - threshold = 4; // An unlock happens when this threshold is reached or passed - unlockers[msg.sender] = 1; // Add starter unlocker addresses, in this example 6 - unlockers[0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2] = 1; - unlockers[0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c] = 1; - unlockers[0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db] = 1; - unlockers[0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB] = 1; - unlockers[0x617F2E2fD72FD9D5503197092aC168c91465E7f2] = 1; - function_locks[0] = 0; // Locked function [0] - unlocker_role_add() - function_locks[1] = 0; // Locked function [1] - unlocker_role_remove() - function_locks[2] = 0; // Locked function [2] - critical_impact1() - function_locks[3] = 0; // Locked function [3] - critical_impact2() - } - - function unlocker_role_add(address new_unlocker) external returns (bool){ - emit major_impact_call(true); - require(unlockers[msg.sender] == 1); - require(function_locks[0] >= threshold); - unlockers[new_unlocker] = 1; - return true; - } - - function unlocker_role_remove(address rem_unlocker) external returns (bool){ - emit major_impact_call(true); - require(unlockers[msg.sender] == 1); - require(function_locks[1] >= threshold); - unlockers[rem_unlocker] = 0; // Alternative option to remove fully - return true; - } - - function unlock_voter(uint256 func_id) external returns (bool){ - require(unlockers[msg.sender] == 1); - unlockers[msg.sender] = 0; // This could be improved, as now everyone can only vote once - function_locks[func_id] = function_locks[func_id] + 1; - return true; - } - - // Voronoi solidity is ready to use after this. - // You can add your ERC20/ERC115 or other code and use the Voronoi security functions - - function critical_impact1() external returns (bool) { - emit major_impact_call(true); - require(function_locks[2] >= threshold); - function_locks[1] = 0; // Can be called only once and threshold is reset. - return true; - } - - function critical_impact2() external returns (bool) { - emit major_impact_call(true); - require(function_locks[3] >= threshold); - function_locks[2] = 0; // Can be called only once and threshold is reset. - return true; - } - - function minor_impact() external returns (bool) { // No unlock check, just execute - emit minor_impact_call(true); - return true; - } -}