pragma solidity ^0.4.18;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
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;
}
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;
}
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) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
uint256 public totalSupply;
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);
}
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
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 REDToken is ERC20, Ownable {
using SafeMath for uint;
/*----------------- Token Information -----------------*/
string public constant name = "Red Community Token";
string public constant symbol = "RED";
uint8 public decimals = 18; // (ERC20 API) Decimal precision, factor is 1e18
mapping (address => uint256) angels; // Angels accounts table (during locking period only)
mapping (address => uint256) accounts; // User's accounts table
mapping (address => mapping (address => uint256)) allowed; // User's allowances table
/*----------------- ICO Information -----------------*/
uint256 public angelSupply; // Angels sale supply
uint256 public earlyBirdsSupply; // Early birds supply
uint256 public publicSupply; // Open round supply
uint256 public foundationSupply; // Red Foundation/Community supply
uint256 public redTeamSupply; // Red team supply
uint256 public marketingSupply; // Marketing & strategic supply
uint256 public angelAmountRemaining; // Amount of private angels tokens remaining at a given time
uint256 public icoStartsAt; // Crowdsale ending timestamp
uint256 public icoEndsAt; // Crowdsale ending timestamp
uint256 public redTeamLockingPeriod; // Locking period for Red team's supply
uint256 public angelLockingPeriod; // Locking period for Angel's supply
address public crowdfundAddress; // Crowdfunding contract address
address public redTeamAddress; // Red team address
address public foundationAddress; // Foundation address
address public marketingAddress; // Private equity address
bool public unlock20Done = false; // Allows the 20% unlocking for angels only once
enum icoStages {
Ready, // Initial state on contract's creation
EarlyBirds, // Early birds state
PublicSale, // Public crowdsale state
Done // Ending state after ICO
}
icoStages stage; // Crowdfunding current state
/*----------------- Events -----------------*/
event EarlyBirdsFinalized(uint tokensRemaining); // Event called when early birds round is done
event CrowdfundFinalized(uint tokensRemaining); // Event called when crowdfund is done
/*----------------- Modifiers -----------------*/
modifier nonZeroAddress(address _to) { // Ensures an address is provided
require(_to != 0x0);
_;
}
modifier nonZeroAmount(uint _amount) { // Ensures a non-zero amount
require(_amount > 0);
_;
}
modifier nonZeroValue() { // Ensures a non-zero value is passed
require(msg.value > 0);
_;
}
modifier onlyDuringCrowdfund(){ // Ensures actions can only happen after crowdfund ends
require((now >= icoStartsAt) && (now < icoEndsAt));
_;
}
modifier notBeforeCrowdfundEnds(){ // Ensures actions can only happen after crowdfund ends
require(now >= icoEndsAt);
_;
}
modifier checkRedTeamLockingPeriod() { // Ensures locking period is over
require(now >= redTeamLockingPeriod);
_;
}
modifier checkAngelsLockingPeriod() { // Ensures locking period is over
require(now >= angelLockingPeriod);
_;
}
modifier onlyCrowdfund() { // Ensures only crowdfund can call the function
require(msg.sender == crowdfundAddress);
_;
}
/*----------------- ERC20 API -----------------*/
// -------------------------------------------------
// Transfers amount to address
// -------------------------------------------------
function transfer(address _to, uint256 _amount) public notBeforeCrowdfundEnds returns (bool success) {
require(accounts[msg.sender] >= _amount); // check amount of balance can be tranfered
addToBalance(_to, _amount);
decrementBalance(msg.sender, _amount);
Transfer(msg.sender, _to, _amount);
return true;
}
// -------------------------------------------------
// Transfers from one address to another (need allowance to be called first)
// -------------------------------------------------
function transferFrom(address _from, address _to, uint256 _amount) public notBeforeCrowdfundEnds returns (bool success) {
require(allowance(_from, msg.sender) >= _amount);
decrementBalance(_from, _amount);
addToBalance(_to, _amount);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_amount);
Transfer(_from, _to, _amount);
return true;
}
// -------------------------------------------------
// Approves another address a certain amount of RED
// -------------------------------------------------
function approve(address _spender, uint256 _value) public returns (bool success) {
require((_value == 0) || (allowance(msg.sender, _spender) == 0));
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
// -------------------------------------------------
// Gets an address's RED allowance
// -------------------------------------------------
function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
// -------------------------------------------------
// Gets the RED balance of any address
// -------------------------------------------------
function balanceOf(address _owner) public constant returns (uint256 balance) {
return accounts[_owner] + angels[_owner];
}
/*----------------- Token API -----------------*/
// -------------------------------------------------
// Contract's constructor
// -------------------------------------------------
function REDToken() public {
totalSupply = 200000000 * 1e18; // 100% - 200 million total RED with 18 decimals
angelSupply = 20000000 * 1e18; // 10% - 20 million RED for private angels sale
earlyBirdsSupply = 48000000 * 1e18; // 24% - 48 million RED for early-bird sale
publicSupply = 12000000 * 1e18; // 6% - 12 million RED for the public crowdsale
redTeamSupply = 30000000 * 1e18; // 15% - 30 million RED for Red team
foundationSupply = 70000000 * 1e18; // 35% - 70 million RED for foundation/incentivising efforts
marketingSupply = 20000000 * 1e18; // 10% - 20 million RED for covering marketing and strategic expenses
angelAmountRemaining = angelSupply; // Decreased over the course of the private angel sale
redTeamAddress = 0x31aa507c140E012d0DcAf041d482e04F36323B03; // Red Team address
foundationAddress = 0x93e3AF42939C163Ee4146F63646Fb4C286CDbFeC; // Foundation/Community address
marketingAddress = 0x0; // Marketing/Strategic address
icoStartsAt = 1515398400; // Jan 8th 2018, 16:00, GMT+8
icoEndsAt = 1517385600; // Jan 31th 2018, 16:00, GMT+8
angelLockingPeriod = icoEndsAt.add(90 days); // 3 months locking period
redTeamLockingPeriod = icoEndsAt.add(365 days); // 12 months locking period
addToBalance(foundationAddress, foundationSupply);
stage = icoStages.Ready; // Initializes state
}
// -------------------------------------------------
// Opens early birds sale
// -------------------------------------------------
function startCrowdfund() external onlyCrowdfund onlyDuringCrowdfund returns(bool) {
require(stage == icoStages.Ready);
stage = icoStages.EarlyBirds;
addToBalance(crowdfundAddress, earlyBirdsSupply);
return true;
}
// -------------------------------------------------
// Returns TRUE if early birds round is currently going on
// -------------------------------------------------
function isEarlyBirdsStage() external view returns(bool) {
return (stage == icoStages.EarlyBirds);
}
// -------------------------------------------------
// Sets the crowdfund address, can only be done once
// -------------------------------------------------
function setCrowdfundAddress(address _crowdfundAddress) external onlyOwner nonZeroAddress(_crowdfundAddress) {
require(crowdfundAddress == 0x0);
crowdfundAddress = _crowdfundAddress;
}
// -------------------------------------------------
// Function for the Crowdfund to transfer tokens
// -------------------------------------------------
function transferFromCrowdfund(address _to, uint256 _amount) external onlyCrowdfund nonZeroAmount(_amount) nonZeroAddress(_to) returns (bool success) {
require(balanceOf(crowdfundAddress) >= _amount);
decrementBalance(crowdfundAddress, _amount);
addToBalance(_to, _amount);
Transfer(0x0, _to, _amount);
return true;
}
// -------------------------------------------------
// Releases Red team supply after locking period is passed
// -------------------------------------------------
function releaseRedTeamTokens() external checkRedTeamLockingPeriod onlyOwner returns(bool success) {
require(redTeamSupply > 0);
addToBalance(redTeamAddress, redTeamSupply);
Transfer(0x0, redTeamAddress, redTeamSupply);
redTeamSupply = 0;
return true;
}
// -------------------------------------------------
// Releases Marketing & strategic supply
// -------------------------------------------------
function releaseMarketingTokens() external onlyOwner returns(bool success) {
require(marketingSupply > 0);
addToBalance(marketingAddress, marketingSupply);
Transfer(0x0, marketingAddress, marketingSupply);
marketingSupply = 0;
return true;
}
// -------------------------------------------------
// Finalizes early birds round. If some RED are left, let them overflow to the crowdfund
// -------------------------------------------------
function finalizeEarlyBirds() external onlyOwner returns (bool success) {
require(stage == icoStages.EarlyBirds);
uint256 amount = balanceOf(crowdfundAddress);
addToBalance(crowdfundAddress, publicSupply);
stage = icoStages.PublicSale;
EarlyBirdsFinalized(amount); // event log
return true;
}
// -------------------------------------------------
// Finalizes crowdfund. If there are leftover RED, let them overflow to foundation
// -------------------------------------------------
function finalizeCrowdfund() external onlyCrowdfund {
require(stage == icoStages.PublicSale);
uint256 amount = balanceOf(crowdfundAddress);
if (amount > 0) {
accounts[crowdfundAddress] = 0;
addToBalance(foundationAddress, amount);
Transfer(crowdfundAddress, foundationAddress, amount);
}
stage = icoStages.Done;
CrowdfundFinalized(amount); // event log
}
// -------------------------------------------------
// Changes Red Team wallet
// -------------------------------------------------
function changeRedTeamAddress(address _wallet) external onlyOwner {
redTeamAddress = _wallet;
}
// -------------------------------------------------
// Changes Marketing&Strategic wallet
// -------------------------------------------------
function changeMarketingAddress(address _wallet) external onlyOwner {
marketingAddress = _wallet;
}
// -------------------------------------------------
// Function to unlock 20% RED to private angels investors
// -------------------------------------------------
function partialUnlockAngelsAccounts(address[] _batchOfAddresses) external onlyOwner notBeforeCrowdfundEnds returns (bool success) {
require(unlock20Done == false);
uint256 amount;
address holder;
for (uint256 i = 0; i < _batchOfAddresses.length; i++) {
holder = _batchOfAddresses[i];
amount = angels[holder].mul(20).div(100);
angels[holder] = angels[holder].sub(amount);
addToBalance(holder, amount);
}
unlock20Done = true;
return true;
}
// -------------------------------------------------
// Function to unlock all remaining RED to private angels investors (after 3 months)
// -------------------------------------------------
function fullUnlockAngelsAccounts(address[] _batchOfAddresses) external onlyOwner checkAngelsLockingPeriod returns (bool success) {
uint256 amount;
address holder;
for (uint256 i = 0; i < _batchOfAddresses.length; i++) {
holder = _batchOfAddresses[i];
amount = angels[holder];
angels[holder] = 0;
addToBalance(holder, amount);
}
return true;
}
// -------------------------------------------------
// Function to reserve RED to private angels investors (initially locked)
// the amount of RED is in Wei
// -------------------------------------------------
function deliverAngelsREDAccounts(address[] _batchOfAddresses, uint[] _amountOfRED) external onlyOwner onlyDuringCrowdfund returns (bool success) {
for (uint256 i = 0; i < _batchOfAddresses.length; i++) {
deliverAngelsREDBalance(_batchOfAddresses[i], _amountOfRED[i]);
}
return true;
}
/*----------------- Helper functions -----------------*/
// -------------------------------------------------
// If one address has contributed more than once,
// the contributions will be aggregated
// -------------------------------------------------
function deliverAngelsREDBalance(address _accountHolder, uint _amountOfBoughtRED) internal onlyOwner {
require(angelAmountRemaining > 0);
angels[_accountHolder] = angels[_accountHolder].add(_amountOfBoughtRED);
Transfer(0x0, _accountHolder, _amountOfBoughtRED);
angelAmountRemaining = angelAmountRemaining.sub(_amountOfBoughtRED);
}
// -------------------------------------------------
// Adds to balance
// -------------------------------------------------
function addToBalance(address _address, uint _amount) internal {
accounts[_address] = accounts[_address].add(_amount);
}
// -------------------------------------------------
// Removes from balance
// -------------------------------------------------
function decrementBalance(address _address, uint _amount) internal {
accounts[_address] = accounts[_address].sub(_amount);
}
}
{
"compilationTarget": {
"REDToken.sol": "REDToken"
},
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[{"name":"_wallet","type":"address"}],"name":"changeMarketingAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"icoStartsAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"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":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"redTeamSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_batchOfAddresses","type":"address[]"},{"name":"_amountOfRED","type":"uint256[]"}],"name":"deliverAngelsREDAccounts","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_batchOfAddresses","type":"address[]"}],"name":"partialUnlockAngelsAccounts","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"angelAmountRemaining","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"publicSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"icoEndsAt","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"marketingSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"crowdfundAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"redTeamAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_batchOfAddresses","type":"address[]"}],"name":"fullUnlockAngelsAccounts","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"foundationSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFromCrowdfund","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"angelLockingPeriod","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"releaseRedTeamTokens","outputs":[{"name":"success","type":"bool"}],"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":"redTeamLockingPeriod","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":"unlock20Done","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"startCrowdfund","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_crowdfundAddress","type":"address"}],"name":"setCrowdfundAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"marketingAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"earlyBirdsSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"finalizeCrowdfund","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"finalizeEarlyBirds","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"angelSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isEarlyBirdsStage","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"releaseMarketingTokens","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_wallet","type":"address"}],"name":"changeRedTeamAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"foundationAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"tokensRemaining","type":"uint256"}],"name":"EarlyBirdsFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"tokensRemaining","type":"uint256"}],"name":"CrowdfundFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]