pragma solidity ^0.4.24;
contract Owned {
address public owner;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
constructor() public {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) public onlyOwner returns (address account) {
owner = newOwner;
return owner;
}
}
library SafeMath {
function add(uint a, uint b) internal pure returns (uint c) {
c = a + b;
require(c >= a);
}
function sub(uint a, uint b) internal pure returns (uint c) {
require(b <= a);
c = a - b;
}
function mul(uint a, uint b) internal pure returns (uint c) {
c = a * b;
require(a == 0 || c / a == b);
}
function div(uint a, uint b) internal pure returns (uint c) {
require(b > 0);
c = a / b;
}
}
contract ERC20 {
function totalSupply() public constant returns (uint256);
function balanceOf(address tokenOwner) public constant returns (uint256 balance);
function allowance(address tokenOwner, address spender) public constant returns (uint256 remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint256 tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint256 tokens);
}
contract CSTKDropToken is ERC20, Owned {
using SafeMath for uint256;
string public symbol;
string public name;
uint256 public decimals;
uint256 _totalSupply;
bool public started;
address public token;
struct Level {
uint256 price;
uint256 available;
}
Level[] levels;
mapping(address => uint256) balances;
mapping(address => mapping(string => uint256)) orders;
event TransferETH(address indexed from, address indexed to, uint256 eth);
event Sell(address indexed to, uint256 tokens, uint256 eth);
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
constructor(string _symbol, string _name, uint256 _supply, uint256 _decimals, address _token) public {
symbol = _symbol;
name = _name;
decimals = _decimals;
token = _token;
_totalSupply = _supply;
balances[owner] = _totalSupply;
started = false;
emit Transfer(address(0), owner, _totalSupply);
}
function destruct() public onlyOwner {
ERC20 tokenInstance = ERC20(token);
uint256 balance = tokenInstance.balanceOf(this);
if (balance > 0) {
tokenInstance.transfer(owner, balance);
}
selfdestruct(owner);
}
// ------------------------------------------------------------------------
// Changes the address of the supported token
// ------------------------------------------------------------------------
function setToken(address newTokenAddress) public onlyOwner returns (bool success) {
token = newTokenAddress;
return true;
}
// ------------------------------------------------------------------------
// Total supply
// ------------------------------------------------------------------------
function totalSupply() public view returns (uint256) {
return _totalSupply.sub(balances[address(0)]);
}
// ------------------------------------------------------------------------
// Changes the total supply value
//
// a new supply must be no less then the current supply
// or the owner must have enough amount to cover supply reduction
// ------------------------------------------------------------------------
function changeTotalSupply(uint256 newSupply) public onlyOwner returns (bool success) {
require(newSupply >= 0 && (
newSupply >= _totalSupply || _totalSupply - newSupply <= balances[owner]
));
uint256 diff = 0;
if (newSupply >= _totalSupply) {
diff = newSupply.sub(_totalSupply);
balances[owner] = balances[owner].add(diff);
emit Transfer(address(0), owner, diff);
} else {
diff = _totalSupply.sub(newSupply);
balances[owner] = balances[owner].sub(diff);
emit Transfer(owner, address(0), diff);
}
_totalSupply = newSupply;
return true;
}
// ------------------------------------------------------------------------
// Get the token balance for account `tokenOwner`
// ------------------------------------------------------------------------
function balanceOf(address tokenOwner) public view returns (uint256 balance) {
return balances[tokenOwner];
}
// ------------------------------------------------------------------------
// Start accept orders
// ------------------------------------------------------------------------
function start() public onlyOwner {
started = true;
}
// ------------------------------------------------------------------------
// Start accept orders
// ------------------------------------------------------------------------
function stop() public onlyOwner {
started = false;
}
// ------------------------------------------------------------------------
// Adds new Level to the levels array
// ------------------------------------------------------------------------
function addLevel(uint256 price, uint256 available) public onlyOwner {
levels.push(Level(price, available));
}
// ------------------------------------------------------------------------
// Removes a level with specified price from the levels array
// ------------------------------------------------------------------------
function removeLevel(uint256 price) public onlyOwner {
if (levels.length < 1) {
return;
}
Level[] memory tmp = levels;
delete levels;
for (uint i = 0; i < tmp.length; i++) {
if (tmp[i].price != price) {
levels.push(tmp[i]);
}
}
}
// ------------------------------------------------------------------------
// Replaces a particular level index by a new Level values
// ------------------------------------------------------------------------
function replaceLevel(uint index, uint256 price, uint256 available) public onlyOwner {
levels[index] = Level(price, available);
}
// ------------------------------------------------------------------------
// Clears the levels array
// ------------------------------------------------------------------------
function clearLevels() public onlyOwner {
delete levels;
}
// ------------------------------------------------------------------------
// Finds a level with specified price and returns an amount of available tokens on the level
// ------------------------------------------------------------------------
function getLevelAmount(uint256 price) public view returns (uint256 available) {
if (levels.length < 1) {
return 0;
}
for (uint i = 0; i < levels.length; i++) {
if (levels[i].price == price) {
return levels[i].available;
}
}
}
// ------------------------------------------------------------------------
// Returns a Level by it's array index
// ------------------------------------------------------------------------
function getLevelByIndex(uint index) public view returns (uint256 price, uint256 available) {
price = levels[index].price;
available = levels[index].available;
}
// ------------------------------------------------------------------------
// Returns a count of levels
// ------------------------------------------------------------------------
function getLevelsCount() public view returns (uint) {
return levels.length;
}
// ------------------------------------------------------------------------
// Returns a Level by it's array index
// ------------------------------------------------------------------------
function getCurrentLevel() public view returns (uint256 price, uint256 available) {
if (levels.length < 1) {
return;
}
for (uint i = 0; i < levels.length; i++) {
if (levels[i].available > 0) {
price = levels[i].price;
available = levels[i].available;
break;
}
}
}
// ------------------------------------------------------------------------
// Get the order's balance of tokens for account `customer`
// ------------------------------------------------------------------------
function orderTokensOf(address customer) public view returns (uint256 balance) {
return orders[customer]['tokens'];
}
// ------------------------------------------------------------------------
// Get the order's balance of ETH for account `customer`
// ------------------------------------------------------------------------
function orderEthOf(address customer) public view returns (uint256 balance) {
return orders[customer]['eth'];
}
// ------------------------------------------------------------------------
// Delete customer's order
// ------------------------------------------------------------------------
function cancelOrder(address customer) public onlyOwner returns (bool success) {
orders[customer]['eth'] = 0;
orders[customer]['tokens'] = 0;
return true;
}
// ------------------------------------------------------------------------
// Checks the order values by the customer's address and sends required
// promo tokens based on the received amount of `this` tokens and ETH
// ------------------------------------------------------------------------
function _checkOrder(address customer) private returns (uint256 tokens, uint256 eth) {
require(started);
eth = 0;
tokens = 0;
if (getLevelsCount() <= 0 || orders[customer]['tokens'] <= 0 || orders[customer]['eth'] <= 0) {
return;
}
ERC20 tokenInstance = ERC20(token);
uint256 balance = tokenInstance.balanceOf(this);
uint256 orderEth = orders[customer]['eth'];
uint256 orderTokens = orders[customer]['tokens'] > balance ? balance : orders[customer]['tokens'];
for (uint i = 0; i < levels.length; i++) {
if (levels[i].available <= 0) {
continue;
}
uint256 _tokens = (10**decimals) * orderEth / levels[i].price;
// check if there enough tokens on the level
if (_tokens > levels[i].available) {
_tokens = levels[i].available;
}
// check the order tokens limit
if (_tokens > orderTokens) {
_tokens = orderTokens;
}
uint256 _eth = _tokens * levels[i].price / (10**decimals);
levels[i].available -= _tokens;
// accumulate total price and tokens
eth += _eth;
tokens += _tokens;
// reduce remaining limits
orderEth -= _eth;
orderTokens -= _tokens;
if (orderEth <= 0 || orderTokens <= 0 || levels[i].available > 0) {
// order is calculated
break;
}
}
// charge required amount of the tokens and ETHs
orders[customer]['tokens'] = orders[customer]['tokens'].sub(tokens);
orders[customer]['eth'] = orders[customer]['eth'].sub(eth);
tokenInstance.transfer(customer, tokens);
emit Sell(customer, tokens, eth);
}
// ------------------------------------------------------------------------
// public entry point for the `_checkOrder` function
// ------------------------------------------------------------------------
function checkOrder(address customer) public onlyOwner returns (uint256 tokens, uint256 eth) {
return _checkOrder(customer);
}
// ------------------------------------------------------------------------
// Transfer the balance from token owner's account to `to` account
// - Owner's account must have sufficient balance to transfer
// - 0 value transfers are allowed
// - only owner is allowed to send tokens to any address
// - not owners can transfer the balance only to owner's address
// ------------------------------------------------------------------------
function transfer(address to, uint256 tokens) public returns (bool success) {
require(msg.sender == owner || to == owner || to == address(this));
address receiver = msg.sender == owner ? to : owner;
balances[msg.sender] = balances[msg.sender].sub(tokens);
balances[receiver] = balances[receiver].add(tokens);
emit Transfer(msg.sender, receiver, tokens);
if (receiver == owner) {
orders[msg.sender]['tokens'] = orders[msg.sender]['tokens'].add(tokens);
_checkOrder(msg.sender);
}
return true;
}
// ------------------------------------------------------------------------
// `allowance` is not allowed
// ------------------------------------------------------------------------
function allowance(address tokenOwner, address spender) public constant returns (uint256 remaining) {
tokenOwner;
spender;
return uint256(0);
}
// ------------------------------------------------------------------------
// `approve` is not allowed
// ------------------------------------------------------------------------
function approve(address spender, uint tokens) public returns (bool success) {
spender;
tokens;
return true;
}
// ------------------------------------------------------------------------
// `transferFrom` is not allowed
// ------------------------------------------------------------------------
function transferFrom(address from, address to, uint256 tokens) public returns (bool success) {
from;
to;
tokens;
return true;
}
// ------------------------------------------------------------------------
// Accept ETH
// ------------------------------------------------------------------------
function () public payable {
owner.transfer(msg.value);
emit TransferETH(msg.sender, address(this), msg.value);
orders[msg.sender]['eth'] = orders[msg.sender]['eth'].add(msg.value);
_checkOrder(msg.sender);
}
// ------------------------------------------------------------------------
// Owner can transfer out any accidentally sent ERC20 tokens
// ------------------------------------------------------------------------
function transferAnyERC20Token(address tokenAddress, uint256 tokens) public onlyOwner returns (bool success) {
return ERC20(tokenAddress).transfer(owner, tokens);
}
// ------------------------------------------------------------------------
// Owner can transfer out promo token
// ------------------------------------------------------------------------
function transferToken(uint256 tokens) public onlyOwner returns (bool success) {
return transferAnyERC20Token(token, tokens);
}
// ------------------------------------------------------------------------
// Owner can return specified amount from `tokenOwner`
// ------------------------------------------------------------------------
function returnFrom(address tokenOwner, uint256 tokens) public onlyOwner returns (bool success) {
balances[tokenOwner] = balances[tokenOwner].sub(tokens);
balances[owner] = balances[owner].add(tokens);
emit Transfer(tokenOwner, owner, tokens);
return true;
}
// ------------------------------------------------------------------------
// Owner can return all tokens from `tokenOwner`
// ------------------------------------------------------------------------
function nullifyFrom(address tokenOwner) public onlyOwner returns (bool success) {
return returnFrom(tokenOwner, balances[tokenOwner]);
}
}
contract CSTK_CLT is CSTKDropToken('CSTK_CLT', 'CryptoStock CLT Promo Token', 100000 * 10**8, 8, 0x2001f2A0Cf801EcFda622f6C28fb6E10d803D969) {
}
{
"compilationTarget": {
"CSTK_CLT.sol": "CSTK_CLT"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"tokens","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newTokenAddress","type":"address"}],"name":"setToken","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"customer","type":"address"}],"name":"orderTokensOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"started","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"tokens","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"destruct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"tokenOwner","type":"address"}],"name":"nullifyFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getLevelsCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"price","type":"uint256"}],"name":"getLevelAmount","outputs":[{"name":"available","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"index","type":"uint256"}],"name":"getLevelByIndex","outputs":[{"name":"price","type":"uint256"},{"name":"available","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newSupply","type":"uint256"}],"name":"changeTotalSupply","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"customer","type":"address"}],"name":"checkOrder","outputs":[{"name":"tokens","type":"uint256"},{"name":"eth","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"index","type":"uint256"},{"name":"price","type":"uint256"},{"name":"available","type":"uint256"}],"name":"replaceLevel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"tokenOwner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentLevel","outputs":[{"name":"price","type":"uint256"},{"name":"available","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"price","type":"uint256"}],"name":"removeLevel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"price","type":"uint256"},{"name":"available","type":"uint256"}],"name":"addLevel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"customer","type":"address"}],"name":"cancelOrder","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tokens","type":"uint256"}],"name":"transferToken","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"tokens","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"start","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tokenOwner","type":"address"},{"name":"tokens","type":"uint256"}],"name":"returnFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tokenAddress","type":"address"},{"name":"tokens","type":"uint256"}],"name":"transferAnyERC20Token","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"tokenOwner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"clearLevels","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"name":"account","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"customer","type":"address"}],"name":"orderEthOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"eth","type":"uint256"}],"name":"TransferETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"tokens","type":"uint256"},{"indexed":false,"name":"eth","type":"uint256"}],"name":"Sell","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"tokens","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"tokenOwner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"tokens","type":"uint256"}],"name":"Approval","type":"event"}]