/** * Source Code first verified at https://etherscan.io on Saturday, April 20, 2019 (UTC) */ pragma solidity ^0.4.24; contract Multiownable { bool public paused = false; uint256 public howManyOwnersDecide; address[] public owners; bytes32[] public allOperations; address internal insideCallSender; uint256 internal insideCallCount; mapping(address => uint) public ownersIndices; // Starts from 1 mapping(bytes32 => uint) public allOperationsIndicies; mapping(bytes32 => uint256) public votesMaskByOperation; mapping(bytes32 => uint256) public votesCountByOperation; 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); event OwnershipRenounced(address indexed previousOwner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); event Pause(); event Unpause(); function isOwner(address wallet) public constant returns(bool) { return ownersIndices[wallet] > 0; } function ownersCount() public view returns(uint) { return owners.length; } function allOperationsCount() public view returns(uint) { return allOperations.length; } modifier onlyAnyOwner { if (checkHowManyOwners(1)) { bool update = (insideCallSender == address(0)); if (update) { insideCallSender = msg.sender; insideCallCount = 1; } _; if (update) { insideCallSender = address(0); insideCallCount = 0; } } } modifier onlyManyOwners { if (checkHowManyOwners(howManyOwnersDecide)) { bool update = (insideCallSender == address(0)); if (update) { insideCallSender = msg.sender; insideCallCount = howManyOwnersDecide; } _; if (update) { insideCallSender = address(0); insideCallCount = 0; } } } constructor() public { } 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)); 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; } 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]; } 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); } } function transferOwnership(address _newOwner, address _oldOwner) public onlyManyOwners { _transferOwnership(_newOwner, _oldOwner); } function _transferOwnership(address _newOwner, address _oldOwner) internal { require(_newOwner != address(0)); for(uint256 i = 0; i < owners.length; i++) { if (_oldOwner == owners[i]) { owners[i] = _newOwner; ownersIndices[_newOwner] = ownersIndices[_oldOwner]; ownersIndices[_oldOwner] = 0; break; } } emit OwnershipTransferred(_oldOwner, _newOwner); } modifier whenNotPaused() { require(!paused); _; } modifier whenPaused() { require(paused); _; } function pause() public onlyManyOwners whenNotPaused { paused = true; emit Pause(); } function unpause() public onlyManyOwners whenPaused { paused = false; emit Unpause(); } } contract GovernanceMigratable is Multiownable { mapping(address => bool) public governanceContracts; event GovernanceContractAdded(address addr); event GovernanceContractRemoved(address addr); modifier onlyGovernanceContracts() { require(governanceContracts[msg.sender]); _; } function addAddressToGovernanceContract(address addr) onlyManyOwners public returns(bool success) { if (!governanceContracts[addr]) { governanceContracts[addr] = true; emit GovernanceContractAdded(addr); success = true; } } function removeAddressFromGovernanceContract(address addr) onlyManyOwners public returns(bool success) { if (governanceContracts[addr]) { governanceContracts[addr] = false; emit GovernanceContractRemoved(addr); success = true; } } } contract BlacklistMigratable is GovernanceMigratable { mapping(address => bool) public blacklist; event BlacklistedAddressAdded(address addr); event BlacklistedAddressRemoved(address addr); function addAddressToBlacklist(address addr) onlyGovernanceContracts() public returns(bool success) { if (!blacklist[addr]) { blacklist[addr] = true; emit BlacklistedAddressAdded(addr); success = true; } } function removeAddressFromBlacklist(address addr) onlyGovernanceContracts() public returns(bool success) { if (blacklist[addr]) { blacklist[addr] = false; emit BlacklistedAddressRemoved(addr); success = true; } } } library SafeMath { function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { if (_a == 0) { return 0; } c = _a * _b; assert(c / _a == _b); return c; } function div(uint256 _a, uint256 _b) internal pure returns (uint256) { return _a / _b; } function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { assert(_b <= _a); return _a - _b; } function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) { c = _a + _b; assert(c >= _a); return c; } } contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address _who) public view returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } contract ERC20 is ERC20Basic { function allowance(address _owner, address _spender) public view returns (uint256); function transferFrom(address _from, address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); event Approval( address indexed owner, address indexed spender, uint256 value ); } contract BasicToken is ERC20Basic { using SafeMath for uint256; mapping(address => uint256) internal balances; uint256 internal totalSupply_; function totalSupply() public view returns (uint256) { return totalSupply_; } function transfer(address _to, uint256 _value) public returns (bool) { require(_value <= balances[msg.sender]); require(_to != address(0)); balances[msg.sender] = balances[msg.sender].sub(_value); balances[_to] = balances[_to].add(_value); emit Transfer(msg.sender, _to, _value); return true; } function balanceOf(address _owner) public view returns (uint256) { return balances[_owner]; } } contract StandardToken is ERC20, BasicToken { mapping (address => mapping (address => uint256)) internal allowed; function transferFrom( address _from, address _to, uint256 _value ) public returns (bool) { require(_value <= balances[_from]); require(_value <= allowed[_from][msg.sender]); require(_to != address(0)); balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); emit Transfer(_from, _to, _value); return true; } function approve(address _spender, uint256 _value) public returns (bool) { allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } function allowance( address _owner, address _spender ) public view returns (uint256) { return allowed[_owner][_spender]; } function increaseApproval( address _spender, uint256 _addedValue ) public returns (bool) { allowed[msg.sender][_spender] = ( allowed[msg.sender][_spender].add(_addedValue)); emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } function decreaseApproval( address _spender, uint256 _subtractedValue ) public returns (bool) { uint256 oldValue = allowed[msg.sender][_spender]; if (_subtractedValue >= oldValue) { allowed[msg.sender][_spender] = 0; } else { allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); } emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } } contract TruePausableToken is StandardToken, BlacklistMigratable { function transfer( address _to, uint256 _value ) public whenNotPaused returns (bool) { require(!blacklist[msg.sender]); return super.transfer(_to, _value); } function transferFrom( address _from, address _to, uint256 _value ) public whenNotPaused returns (bool) { require(!blacklist[_from]); return super.transferFrom(_from, _to, _value); } function approve( address _spender, uint256 _value ) public whenNotPaused returns (bool) { return super.approve(_spender, _value); } function increaseApproval( address _spender, uint _addedValue ) public whenNotPaused returns (bool success) { return super.increaseApproval(_spender, _addedValue); } function decreaseApproval( address _spender, uint _subtractedValue ) public whenNotPaused returns (bool success) { return super.decreaseApproval(_spender, _subtractedValue); } } contract DetailedERC20 is ERC20 { string public name; string public symbol; uint8 public decimals; constructor(string _name, string _symbol, uint8 _decimals) public { name = _name; symbol = _symbol; decimals = _decimals; } } contract TrueBurnableToken is BasicToken { event Burn(address indexed burner, uint256 value); function _burn(address _who, uint256 _value) internal { require(_value <= balances[_who]); balances[_who] = balances[_who].sub(_value); totalSupply_ = totalSupply_.sub(_value); emit Burn(_who, _value); emit Transfer(_who, address(0), _value); } } contract USDQToken is StandardToken, TrueBurnableToken, DetailedERC20, TruePausableToken { event Mint(address indexed to, uint256 amount); uint8 constant DECIMALS = 18; constructor(address _firstOwner, address _secondOwner, address _thirdOwner, address _fourthOwner, address _fifthOwner) DetailedERC20("USDQ Stablecoin by Q DAO v1.0", "USDQ", DECIMALS) public { owners.push(_firstOwner); owners.push(_secondOwner); owners.push(_thirdOwner); owners.push(_fourthOwner); owners.push(_fifthOwner); owners.push(msg.sender); ownersIndices[_firstOwner] = 1; ownersIndices[_secondOwner] = 2; ownersIndices[_thirdOwner] = 3; ownersIndices[_fourthOwner] = 4; ownersIndices[_fifthOwner] = 5; ownersIndices[msg.sender] = 6; howManyOwnersDecide = 4; } function mint(address _to, uint256 _amount) external onlyGovernanceContracts() returns (bool){ totalSupply_ = totalSupply_.add(_amount); balances[_to] = balances[_to].add(_amount); emit Mint(_to, _amount); emit Transfer(address(0), _to, _amount); return true; } function approveForOtherContracts(address _sender, address _spender, uint256 _value) external onlyGovernanceContracts() { allowed[_sender][_spender] = _value; emit Approval(_sender, _spender, _value); } function burnFrom(address _to, uint256 _amount) external onlyGovernanceContracts() returns (bool) { allowed[_to][msg.sender] = _amount; transferFrom(_to, msg.sender, _amount); _burn(msg.sender, _amount); return true; } }