pragma solidity ^0.5.0;
interface PriceWatcherI
{
function getUSDcentsPerETH() external view returns (uint256 _USDcentsPerETH);
}
contract PriceWatcherPlaceholder is PriceWatcherI
{
function getUSDcentsPerETH() external view returns (uint256 _USDcentsPerETH)
{
return 12345; // $123.45 per ETH
}
}
contract Super100
{
// Constants
uint256 public TOKEN_PRICE_USD_CENTS;
uint256 public totalSupply;
uint256 public AMOUNT_OF_FREE_TOKENS;
address payable public root;
address payable public bank;
uint256 public REFERRER_COMMISSION_PERCENTAGE;
uint256 public ROOT_COMMISSION_PERCENTAGE;
PriceWatcherI public priceWatcher;
// State variables
mapping(address => uint256) private balances;
address[] public participants;
mapping(address => address payable) public address_to_referrer;
mapping(address => address[]) public address_to_referrals;
constructor(address _priceWatcherContract, uint256 _tokenPriceUSDcents, uint256 _totalSupply, uint256 _amountOfFreeTokens, address payable _root, address payable _bank, uint256 _referrerCommissionPercentage, uint256 _rootCommissionPercentage) public
{
if (_priceWatcherContract == address(0x0))
{
priceWatcher = new PriceWatcherPlaceholder();
}
else
{
priceWatcher = PriceWatcherI(_priceWatcherContract);
}
TOKEN_PRICE_USD_CENTS = _tokenPriceUSDcents;
totalSupply = _totalSupply;
AMOUNT_OF_FREE_TOKENS = _amountOfFreeTokens;
root = _root;
bank = _bank;
REFERRER_COMMISSION_PERCENTAGE = _referrerCommissionPercentage;
ROOT_COMMISSION_PERCENTAGE = _rootCommissionPercentage;
// The root address is its own referrer
address_to_referrer[root] = root;
// Mint all the tokens and assign them to the root address
balances[root] = totalSupply;
emit Transfer(address(0x0), root, totalSupply);
}
function getTokenPriceETH() public view returns (uint256)
{
// Fetch the current ETH exchange rate
uint256 USDcentsPerETH = priceWatcher.getUSDcentsPerETH();
// Use the exchange rate to calculate the current token price in ETH
return (1 ether) * TOKEN_PRICE_USD_CENTS / USDcentsPerETH;
}
function buyTokens(address payable _referrer) external payable
{
uint256 tokensBought;
uint256 totalValueOfTokensBought;
uint256 tokenPriceWei = getTokenPriceETH();
// If there are still free tokens available
if (participants.length < AMOUNT_OF_FREE_TOKENS)
{
tokensBought = 1;
totalValueOfTokensBought = 0;
// Only 1 free token per address
require(address_to_referrer[msg.sender] == address(0x0));
}
// If there are no free tokens available
else
{
tokensBought = msg.value / tokenPriceWei;
// Limit the bought tokens to the amount of tokens still for sale
if (tokensBought > balances[root])
{
tokensBought = balances[root];
}
totalValueOfTokensBought = tokensBought * tokenPriceWei;
}
// If 0 tokens are being purchased, cancel this transaction
require(tokensBought > 0);
// Return the change
msg.sender.transfer(msg.value - totalValueOfTokensBought);
// If we haven't seen this buyer before
if (address_to_referrer[msg.sender] == address(0x0))
{
// Referrer must have owned at least 1 token
require(address_to_referrer[_referrer] != address(0x0));
// Add them to the particpants list and the referral tree
address_to_referrer[msg.sender] = _referrer;
address_to_referrals[_referrer].push(msg.sender);
participants.push(msg.sender);
}
// If we have seen this buyer before
else
{
// Referrer must be the same as their previous referrer
require(_referrer == address_to_referrer[msg.sender]);
}
// Transfer the bought tokens from root to the buyer
balances[root] -= tokensBought;
balances[msg.sender] += tokensBought;
emit Transfer(root, msg.sender, tokensBought);
// Transfer commission to the referrer
uint256 commissionForReferrer = totalValueOfTokensBought * REFERRER_COMMISSION_PERCENTAGE / 100;
_referrer.transfer(commissionForReferrer);
// Transfer commission to the root
uint256 commissionForRoot = totalValueOfTokensBought * ROOT_COMMISSION_PERCENTAGE / 100;
root.transfer(commissionForRoot);
// Transfer the remaining ETH to the bank
bank.transfer(totalValueOfTokensBought - commissionForReferrer - commissionForRoot);
}
function amountOfReferralsMade(address _byReferrer) external view returns (uint256)
{
return address_to_referrals[_byReferrer].length;
}
function amountOfTokensForSale() external view returns (uint256)
{
return balances[root];
}
function amountOfFreeTokensAvailable() external view returns (uint256)
{
if (participants.length < AMOUNT_OF_FREE_TOKENS)
{
return AMOUNT_OF_FREE_TOKENS - participants.length;
}
else
{
return 0;
}
}
// ERC20 implementation
string public constant name = "Super100";
string public constant symbol = "S100";
uint8 public constant decimals = 0;
mapping (address => mapping (address => uint256)) private allowed;
event Transfer(address indexed _from, address indexed _to, uint256 _amount);
event Approval(address indexed _owner, address indexed _spender, uint256 _amount);
function balanceOf(address _who) external view returns (uint256)
{
return balances[_who];
}
function allowance(address _owner, address _spender) external view returns (uint256)
{
return allowed[_owner][_spender];
}
function transfer(address _to, uint256 _amount) external returns (bool)
{
require(balances[msg.sender] >= _amount);
balances[msg.sender] -= _amount;
balances[_to] += _amount;
emit Transfer(msg.sender, _to, _amount);
return true;
}
function transferFrom(address _from, address _to, uint256 _amount) external returns (bool)
{
require(allowed[_from][msg.sender] >= _amount);
require(balances[_from] >= _amount);
allowed[_from][msg.sender] -= _amount;
balances[_from] -= _amount;
balances[_to] += _amount;
emit Transfer(_from, _to, _amount);
emit Approval(_from, msg.sender, allowed[_from][msg.sender]);
return true;
}
function approve(address _spender, uint256 _amount) external returns (bool)
{
allowed[msg.sender][_spender] = _amount;
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function increaseAllowance(address _spender, uint256 _addedAmount) public returns (bool)
{
require(allowed[msg.sender][_spender] + _addedAmount >= _addedAmount);
allowed[msg.sender][_spender] += _addedAmount;
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function decreaseAllowance(address _spender, uint256 _subtractedAmount) public returns (bool)
{
require(allowed[msg.sender][_spender] >= _subtractedAmount);
allowed[msg.sender][_spender] -= _subtractedAmount;
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
{
"compilationTarget": {
"Super100.sol": "Super100"
},
"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":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"priceWatcher","outputs":[{"name":"","type":"address"}],"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":"","type":"address"}],"name":"address_to_referrer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"participants","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"address_to_referrals","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedAmount","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"REFERRER_COMMISSION_PERCENTAGE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"amountOfTokensForSale","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AMOUNT_OF_FREE_TOKENS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bank","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTokenPriceETH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"TOKEN_PRICE_USD_CENTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_byReferrer","type":"address"}],"name":"amountOfReferralsMade","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedAmount","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ROOT_COMMISSION_PERCENTAGE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"amountOfFreeTokensAvailable","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"root","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referrer","type":"address"}],"name":"buyTokens","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"inputs":[{"name":"_priceWatcherContract","type":"address"},{"name":"_tokenPriceUSDcents","type":"uint256"},{"name":"_totalSupply","type":"uint256"},{"name":"_amountOfFreeTokens","type":"uint256"},{"name":"_root","type":"address"},{"name":"_bank","type":"address"},{"name":"_referrerCommissionPercentage","type":"uint256"},{"name":"_rootCommissionPercentage","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"Approval","type":"event"}]