Skip to content

Instantly share code, notes, and snippets.

@snidima
Last active October 29, 2018 11:32
Show Gist options
  • Select an option

  • Save snidima/1a5c350ff0c7a25e944810857f949b88 to your computer and use it in GitHub Desktop.

Select an option

Save snidima/1a5c350ff0c7a25e944810857f949b88 to your computer and use it in GitHub Desktop.
pragma solidity 0.4.25;
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract Multiownable {
// VARIABLES
uint256 public ownersGeneration;
uint256 public howManyOwnersDecide;
address[] public owners;
bytes32[] public allOperations;
address internal insideCallSender;
uint256 internal insideCallCount;
// Reverse lookup tables for owners and allOperations
mapping(address => uint) public ownersIndices; // Starts from 1
mapping(bytes32 => uint) public allOperationsIndicies;
// Owners voting mask per operations
mapping(bytes32 => uint256) public votesMaskByOperation;
mapping(bytes32 => uint256) public votesCountByOperation;
// EVENTS
event OwnershipTransferred(address[] previousOwners, uint howManyOwnersDecide, address[] newOwners, uint newHowManyOwnersDecide);
event OperationCreated(bytes32 operation, uint howMany, uint ownersCount, address proposer);
event OperationUpvoted(bytes32 operation, uint votes, uint howMany, uint ownersCount, address upvoter);
event OperationPerformed(bytes32 operation, uint howMany, uint ownersCount, address performer);
event OperationDownvoted(bytes32 operation, uint votes, uint ownersCount, address downvoter);
event OperationCancelled(bytes32 operation, address lastCanceller);
// ACCESSORS
function isOwner(address wallet) public constant returns(bool) {
return ownersIndices[wallet] > 0;
}
function ownersCount() public constant returns(uint) {
return owners.length;
}
function allOperationsCount() public constant returns(uint) {
return allOperations.length;
}
// MODIFIERS
/**
* @dev Allows to perform method by any of the owners
*/
modifier onlyAnyOwner {
if (checkHowManyOwners(1)) {
bool update = (insideCallSender == address(0));
if (update) {
insideCallSender = msg.sender;
insideCallCount = 1;
}
_;
if (update) {
insideCallSender = address(0);
insideCallCount = 0;
}
}
}
/**
* @dev Allows to perform method only after many owners call it with the same arguments
*/
modifier onlyManyOwners {
if (checkHowManyOwners(howManyOwnersDecide)) {
bool update = (insideCallSender == address(0));
if (update) {
insideCallSender = msg.sender;
insideCallCount = howManyOwnersDecide;
}
_;
if (update) {
insideCallSender = address(0);
insideCallCount = 0;
}
}
}
/**
* @dev Allows to perform method only after all owners call it with the same arguments
*/
modifier onlyAllOwners {
if (checkHowManyOwners(owners.length)) {
bool update = (insideCallSender == address(0));
if (update) {
insideCallSender = msg.sender;
insideCallCount = owners.length;
}
_;
if (update) {
insideCallSender = address(0);
insideCallCount = 0;
}
}
}
/**
* @dev Allows to perform method only after some owners call it with the same arguments
*/
modifier onlySomeOwners(uint howMany) {
require(howMany > 0, "onlySomeOwners: howMany argument is zero");
require(howMany <= owners.length, "onlySomeOwners: howMany argument exceeds the number of owners");
if (checkHowManyOwners(howMany)) {
bool update = (insideCallSender == address(0));
if (update) {
insideCallSender = msg.sender;
insideCallCount = howMany;
}
_;
if (update) {
insideCallSender = address(0);
insideCallCount = 0;
}
}
}
// CONSTRUCTOR
constructor() public {
owners.push(msg.sender);
ownersIndices[msg.sender] = 1;
howManyOwnersDecide = 1;
}
// INTERNAL METHODS
/**
* @dev onlyManyOwners modifier helper
*/
function checkHowManyOwners(uint howMany) internal returns(bool) {
if (insideCallSender == msg.sender) {
require(howMany <= insideCallCount, "checkHowManyOwners: nested owners modifier check require more owners");
return true;
}
uint ownerIndex = ownersIndices[msg.sender] - 1;
require(ownerIndex < owners.length, "checkHowManyOwners: msg.sender is not an owner");
bytes32 operation = keccak256(abi.encodePacked(msg.data, ownersGeneration));
require((votesMaskByOperation[operation] & (2 ** ownerIndex)) == 0, "checkHowManyOwners: owner already voted for the operation");
votesMaskByOperation[operation] |= (2 ** ownerIndex);
uint operationVotesCount = votesCountByOperation[operation] + 1;
votesCountByOperation[operation] = operationVotesCount;
if (operationVotesCount == 1) {
allOperationsIndicies[operation] = allOperations.length;
allOperations.push(operation);
emit OperationCreated(operation, howMany, owners.length, msg.sender);
}
emit OperationUpvoted(operation, operationVotesCount, howMany, owners.length, msg.sender);
// If enough owners confirmed the same operation
if (votesCountByOperation[operation] == howMany) {
deleteOperation(operation);
emit OperationPerformed(operation, howMany, owners.length, msg.sender);
return true;
}
return false;
}
/**
* @dev Used to delete cancelled or performed operation
* @param operation defines which operation to delete
*/
function deleteOperation(bytes32 operation) internal {
uint index = allOperationsIndicies[operation];
if (index < allOperations.length - 1) { // Not last
allOperations[index] = allOperations[allOperations.length - 1];
allOperationsIndicies[allOperations[index]] = index;
}
allOperations.length--;
delete votesMaskByOperation[operation];
delete votesCountByOperation[operation];
delete allOperationsIndicies[operation];
}
// PUBLIC METHODS
/**
* @dev Allows owners to change their mind by cacnelling votesMaskByOperation operations
* @param operation defines which operation to delete
*/
function cancelPending(bytes32 operation) public onlyAnyOwner {
uint ownerIndex = ownersIndices[msg.sender] - 1;
require((votesMaskByOperation[operation] & (2 ** ownerIndex)) != 0, "cancelPending: operation not found for this user");
votesMaskByOperation[operation] &= ~(2 ** ownerIndex);
uint operationVotesCount = votesCountByOperation[operation] - 1;
votesCountByOperation[operation] = operationVotesCount;
emit OperationDownvoted(operation, operationVotesCount, owners.length, msg.sender);
if (operationVotesCount == 0) {
deleteOperation(operation);
emit OperationCancelled(operation, msg.sender);
}
}
/**
* @dev Allows owners to change ownership
* @param newOwners defines array of addresses of new owners
*/
function transferOwnership(address[] newOwners) public {
transferOwnershipWithHowMany(newOwners, newOwners.length);
}
/**
* @dev Allows owners to change ownership
* @param newOwners defines array of addresses of new owners
* @param newHowManyOwnersDecide defines how many owners can decide
*/
function transferOwnershipWithHowMany(address[] newOwners, uint256 newHowManyOwnersDecide) public onlyManyOwners {
require(newOwners.length > 0, "transferOwnershipWithHowMany: owners array is empty");
require(newOwners.length <= 256, "transferOwnershipWithHowMany: owners count is greater then 256");
require(newHowManyOwnersDecide > 0, "transferOwnershipWithHowMany: newHowManyOwnersDecide equal to 0");
require(newHowManyOwnersDecide <= newOwners.length, "transferOwnershipWithHowMany: newHowManyOwnersDecide exceeds the number of owners");
// Reset owners reverse lookup table
for (uint j = 0; j < owners.length; j++) {
delete ownersIndices[owners[j]];
}
for (uint i = 0; i < newOwners.length; i++) {
require(newOwners[i] != address(0), "transferOwnershipWithHowMany: owners array contains zero");
require(ownersIndices[newOwners[i]] == 0, "transferOwnershipWithHowMany: owners array contains duplicates");
ownersIndices[newOwners[i]] = i + 1;
}
emit OwnershipTransferred(owners, howManyOwnersDecide, newOwners, newHowManyOwnersDecide);
owners = newOwners;
howManyOwnersDecide = newHowManyOwnersDecide;
allOperations.length = 0;
ownersGeneration++;
}
}
contract ERC820Registry {
function getManager(address addr) public view returns(address);
function setManager(address addr, address newManager) public;
function getInterfaceImplementer(address addr, bytes32 iHash) public constant returns (address);
function setInterfaceImplementer(address addr, bytes32 iHash, address implementer) public;
}
contract ERC820Implementer {
ERC820Registry erc820Registry = ERC820Registry(0x991a1bcb077599290d7305493c9A630c20f8b798);
function setInterfaceImplementation(string ifaceLabel, address impl) internal {
bytes32 ifaceHash = keccak256(abi.encodePacked(ifaceLabel));
erc820Registry.setInterfaceImplementer(this, ifaceHash, impl);
}
function interfaceAddr(address addr, string ifaceLabel) internal constant returns(address) {
bytes32 ifaceHash = keccak256(abi.encodePacked(ifaceLabel));
return erc820Registry.getInterfaceImplementer(addr, ifaceHash);
}
function delegateManagement(address newManager) internal {
erc820Registry.setManager(this, newManager);
}
}
interface ERC777TokensSender {
function tokensToSend(address operator, address from, address to, uint amount, bytes userData,bytes operatorData) external;
}
interface ERC777TokensRecipient {
function tokensReceived(address operator, address from, address to, uint amount, bytes userData, bytes operatorData) external;
}
contract ERC777 is ERC820Implementer {
using SafeMath for uint256;
string public name;
string public symbol;
uint8 public decimals;
uint256 public granularity;
uint256 public totalSupply;
event Transfer(address indexed from, address indexed to, uint256 value);
event Sent(address indexed operator, address indexed from, address indexed to, uint256 amount, bytes userData, bytes operatorData);
event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
event RevokedOperator(address indexed operator, address indexed tokenHolder);
event Approval(address indexed owner, address indexed spender, uint256 value);
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => bool)) public isOperatorFor;
/**
* @notice Send `_amount` of tokens to address `_to` passing `_userData` to the recipient
* @param _to The address of the recipient
* @param _amount The number of tokens to be sent
* @param _userData Data generated by the user to be sent to the recipient
*/
function send(address _to, uint256 _amount, bytes _userData) public {
doSend(msg.sender, _to, _amount, _userData, msg.sender, "", true);
}
/**
* @notice Authorize a third party `_operator` to manage (send) `msg.sender`'s tokens.
* @param _operator The operator that wants to be Authorized
*/
function authorizeOperator(address _operator) public {
require(_operator != msg.sender);
isOperatorFor[_operator][msg.sender] = true;
emit AuthorizedOperator(_operator, msg.sender);
}
/**
* @notice Revoke a third party `_operator`'s rights to manage (send) `msg.sender`'s tokens.
* @param _operator The operator that wants to be Revoked
*/
function revokeOperator(address _operator) public {
require(_operator != msg.sender);
isOperatorFor[_operator][msg.sender] = false;
emit RevokedOperator(_operator, msg.sender);
}
/**
* @notice Send `_amount` of tokens on behalf of the address `from` to the address `to`.
* @param _from The address holding the tokens being sent
* @param _to The address of the recipient
* @param _amount The number of tokens to be sent
* @param _userData Data generated by the user to be sent to the recipient
* @param _operatorData Data generated by the operator to be sent to the recipient
*/
function operatorSend(address _from, address _to, uint256 _amount, bytes _userData, bytes _operatorData) public {
require(isOperatorFor[msg.sender][_from]);
doSend(_from, _to, _amount, _userData, msg.sender, _operatorData, true);
}
/* -- Helper Functions -- */
/**
* @notice Internal function that ensures `_amount` is multiple of the granularity
* @param _amount The quantity that want's to be checked
*/
function requireMultiple(uint256 _amount) internal view {
require(_amount.div(granularity).mul(granularity) == _amount);
}
/**
* @notice Check whether an address is a regular address or not.
* @param _addr Address of the contract that has to be checked
* @return `true` if `_addr` is a regular address (not a contract)
*/
function isRegularAddress(address _addr) internal constant returns(bool) {
if (_addr == 0) { return false; }
uint size;
assembly { size := extcodesize(_addr) } // solhint-disable-line no-inline-assembly
return size == 0;
}
/**
* @notice Helper function that checks for ERC777TokensSender on the sender and calls it.
* May throw according to `_preventLocking`
* @param _from The address holding the tokens being sent
* @param _to The address of the recipient
* @param _amount The amount of tokens to be sent
* @param _userData Data generated by the user to be passed to the recipient
* @param _operatorData Data generated by the operator to be passed to the recipient
* implementing `ERC777TokensSender`.
* ERC777 native Send functions MUST set this parameter to `true`, and backwards compatible ERC20 transfer
* functions SHOULD set this parameter to `false`.
*/
function callSender(
address _operator,
address _from,
address _to,
uint256 _amount,
bytes _userData,
bytes _operatorData
) private {
address senderImplementation = interfaceAddr(_from, "ERC777TokensSender");
if (senderImplementation != 0) {
ERC777TokensSender(senderImplementation).tokensToSend(
_operator, _from, _to, _amount, _userData, _operatorData);
}
}
/**
* @notice Helper function that checks for ERC777TokensRecipient on the recipient and calls it.
* May throw according to `_preventLocking`
* @param _from The address holding the tokens being sent
* @param _to The address of the recipient
* @param _amount The number of tokens to be sent
* @param _userData Data generated by the user to be passed to the recipient
* @param _operatorData Data generated by the operator to be passed to the recipient
* @param _preventLocking `true` if you want this function to throw when tokens are sent to a contract not
* implementing `ERC777TokensRecipient`.
* ERC777 native Send functions MUST set this parameter to `true`, and backwards compatible ERC20 transfer
* functions SHOULD set this parameter to `false`.
*/
function callRecipient(
address _operator,
address _from,
address _to,
uint256 _amount,
bytes _userData,
bytes _operatorData,
bool _preventLocking
) private {
address recipientImplementation = interfaceAddr(_to, "ERC777TokensRecipient");
if (recipientImplementation != 0) {
ERC777TokensRecipient(recipientImplementation).tokensReceived(
_operator, _from, _to, _amount, _userData, _operatorData);
} else if (_preventLocking) {
require(isRegularAddress(_to));
}
}
/**
* @notice Helper function actually performing the sending of tokens.
* @param _from The address holding the tokens being sent
* @param _to The address of the recipient
* @param _amount The number of tokens to be sent
* @param _userData Data generated by the user to be passed to the recipient
* @param _operatorData Data generated by the operator to be passed to the recipient
* @param _preventLocking `true` if you want this function to throw when tokens are sent to a contract not
* implementing `erc777_tokenHolder`.
* ERC777 native Send functions MUST set this parameter to `true`, and backwards compatible ERC20 transfer
* functions SHOULD set this parameter to `false`.
*/
function doSend(
address _from,
address _to,
uint256 _amount,
bytes _userData,
address _operator,
bytes _operatorData,
bool _preventLocking
)
private
{
requireMultiple(_amount);
callSender(_operator, _from, _to, _amount, _userData, _operatorData);
require(_to != 0x0);
require(balanceOf[_from] >= _amount);
balanceOf[_from] = balanceOf[_from].sub(_amount);
balanceOf[_to] = balanceOf[_to].add(_amount);
callRecipient(_operator, _from, _to, _amount, _userData, _operatorData, _preventLocking);
emit Sent(_operator, _from, _to, _amount, _userData, _operatorData);
emit Transfer(_from, _to, _amount);
}
// ------- ERC20 Implementation ----------
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
doSend(msg.sender, _to, _value, "", msg.sender, "", false);
return true;
}
/**
* @dev Transfer tokens from one address to another. Technically this is not ERC20 transferFrom but more ERC777 operatorSend.
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(isOperatorFor[msg.sender][_from]);
doSend(_from, _to, _value, "", msg.sender, "", true);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev Originally in ERC20 this function to check the amount of tokens that an owner allowed to a spender.
*
* Function was added purly for backward compatibility with ERC20. Use operator logic from ERC777 instead.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A returning uint256 balanceOf _spender if it's active operator and 0 if not.
*/
function allowance(address _owner, address _spender) public view returns (uint256 _amount) {
if (isOperatorFor[_spender][_owner]) {
_amount = balanceOf[_owner];
} else {
_amount = 0;
}
}
/**
* @dev Approve the passed address to spend tokens on behalf of msg.sender.
*
* This function is more authorizeOperator and revokeOperator from ERC777 that Approve from ERC20.
* Approve concept has several issues (e.g. https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729),
* so I prefer to use operator concept. If you want to revoke approval, just put 0 into _value.
* @param _spender The address which will spend the funds.
* @param _value Fake value to be compatible with ERC20 requirements.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
require(_spender != msg.sender);
if (_value > 0) {
// Authorizing operator
isOperatorFor[_spender][msg.sender] = true;
emit AuthorizedOperator(_spender, msg.sender);
} else {
// Revoking operator
isOperatorFor[_spender][msg.sender] = false;
emit RevokedOperator(_spender, msg.sender);
}
emit Approval(msg.sender, _spender, _value);
return true;
}
}
contract DEC is Multiownable, ERC777 {
using SafeMath for uint256;
uint256 public price = 0.00024 ether;
address public developmentAccount;
uint256 public timeOfSilence = 5 minutes;
bool public websiteSaleSign = false;
bool public investmentSign = false;
mapping( address => uint256 ) public nodeDeposit;
mapping ( uint256 => uint256 ) public balanceOfGroup;
mapping( address => bool ) whitelist;
mapping( uint256 => address[] ) public poolAddresses;
mapping( uint256 => uint256[] ) public poolAmounts;
mapping( address => uint256 ) pushedTokensTime;
mapping( address => uint256 ) pushedTokensAmount;
mapping( address => bool ) public isPushed;
uint256[] poolArray= [11,12,13,21,22,31,32,33,34,41,42,43,51,52];
constructor() public {
name = "Dec Nodes";
symbol = "DEC";
decimals = 18;
granularity = 1;
balanceOfGroup[11] = 35740000000 ether;
balanceOfGroup[12] = 637000000 ether;
balanceOfGroup[13] = 15000000 ether;
balanceOfGroup[21] = 315000000 ether;
balanceOfGroup[22] = 3500000 ether;
balanceOfGroup[31] = 500000 ether;
balanceOfGroup[32] = 15000000 ether;
balanceOfGroup[33] = 16500000 ether;
balanceOfGroup[34] = 9000000 ether;
balanceOfGroup[41] = 433000000 ether;
balanceOfGroup[42] = 34000000 ether;
balanceOfGroup[43] = 303000000 ether;
balanceOfGroup[51] = 15000000 ether;
balanceOfGroup[52] = 112000000 ether;
for (uint256 i = 0; i < poolArray.length; i++) {
totalSupply+= balanceOfGroup[poolArray[i]];
}
balanceOf[address( this )] = totalSupply;
emit Transfer(0x0, address( this ), totalSupply);
}
function setWebsiteSaleSign() public onlyManyOwners
{
websiteSaleSign = true;
}
function setInvestmentSign( address[] _addresses, uint256[] _amounts, uint256 _pool ) public onlyManyOwners
{
investmentSign = true;
}
function setPrice( uint256 _price ) public onlyAnyOwner
{
price = _price;
}
function setPool( address[] _addresses, uint256[] _amounts, uint256 _pool ) public onlyAnyOwner
{
require( _addresses.length == _amounts.length );
if( _pool == 12) {
require( investmentSign );
investmentSign = false;
}
if( _pool == 13) {
require( websiteSaleSign );
}
uint256 sum = 0;
for (uint256 i = 0; i < _amounts.length; i++) {
sum = sum.add( _amounts[i] );
}
require( sum <= balanceOfGroup[_pool] );
poolAddresses[_pool] = _addresses;
poolAmounts[_pool] = _amounts;
}
function Send() public
{
for (uint256 i = 0; i < poolArray.length; i++) {
for (uint256 j = 0; j < poolAddresses[ poolArray[i] ].length; j++) {
uint256 _amount = poolAmounts[poolArray[i]][j];
balanceOf[address(this)] = balanceOf[address(this)].sub(_amount);
balanceOf[poolAddresses[poolArray[i]][j]] = balanceOf[poolAddresses[poolArray[i]][j]].add( _amount );
balanceOfGroup[poolArray[i]] = balanceOfGroup[poolArray[i]].sub( _amount );
poolAmounts[poolArray[i]][j] = 0;
emit Transfer(address( this ), poolAddresses[poolArray[i]][j], _amount);
}
}
}
function insertToWhiteList( address[] _addresses ) public onlyAnyOwner
{
for (uint256 i = 0; i < _addresses.length; i++) {
whitelist[_addresses[i]] = true;
}
}
function removeFromWhiteList( address[] _addresses ) public onlyAnyOwner
{
for (uint256 i = 0; i < _addresses.length; i++) {
whitelist[_addresses[i]] = false;
}
}
function inWhiteList( address _address ) public view returns( bool )
{
return whitelist[_address];
}
function buy () payable public
{
uint256 _amount = msg.value.div( price ) * 1 ether;
require( whitelist[msg.sender] && websiteSaleSign && ( _amount <= balanceOfGroup[13] ) );
requireMultiple( _amount );
balanceOf[ address(this) ] = balanceOf[ address(this) ].sub( _amount );
balanceOf[ msg.sender ] = balanceOf[ msg.sender ].add( _amount );
balanceOfGroup[13] = balanceOfGroup[13].sub( _amount );
}
function pushTokens( uint256 _amount ) public
{
require( isPushed[msg.sender] == false && balanceOf[msg.sender] >= _amount );
pushedTokensTime[msg.sender] = now;
pushedTokensAmount[msg.sender] = _amount;
isPushed[msg.sender] = true;
balanceOf[msg.sender] = balanceOf[msg.sender].sub( _amount );
emit Transfer( msg.sender, address(this), _amount);
}
function pullTokens() public
{
require( isPushed[msg.sender] );
require( pushedTokensTime[msg.sender] + timeOfSilence <= now );
balanceOf[msg.sender] = balanceOf[msg.sender].add( pushedTokensAmount[msg.sender] );
isPushed[msg.sender] = false;
pushedTokensAmount[msg.sender] = 0;
emit Transfer( address(this), msg.sender, pushedTokensAmount[msg.sender]);
}
function accept( address _address ) public onlyAnyOwner
{
require( pushedTokensAmount[_address] > 0 && now <= pushedTokensTime[_address] + timeOfSilence );
nodeDeposit[ _address ] = nodeDeposit[ _address ].add( pushedTokensAmount[_address] );
isPushed[_address] = false;
pushedTokensAmount[_address] = 0;
}
function sendFromDeposit( address _address, uint256 _amount ) public onlyAnyOwner
{
require( nodeDeposit[ _address ] >= _amount );
nodeDeposit[ _address ] = nodeDeposit[ _address ].sub( _amount );
balanceOf[_address] = balanceOf[_address].add( _amount );
emit Transfer( address(this),_address , _amount);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment