Skip to content

Instantly share code, notes, and snippets.

@cmaliwal
Created May 8, 2018 08:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cmaliwal/6ff33c7d75886fc2f10948b41334de37 to your computer and use it in GitHub Desktop.
Save cmaliwal/6ff33c7d75886fc2f10948b41334de37 to your computer and use it in GitHub Desktop.
pragma solidity ^0.4.17;
/**
* @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 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));
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
/**
* @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 Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
/**
* @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) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}
/**
* @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);
}
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
/**
* @dev Transfer tokens from one address to another
* @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(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
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;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
*
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address _owner, address _spender) public view returns (uint256) {
return allowed[_owner][_spender];
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
*
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _addedValue The amount of tokens to increase the allowance by.
*/
function increaseApproval(address _spender, uint _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;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
*
* approve should be called when allowed[_spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
uint 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;
}
}
/**
* @title Mintable token
* @dev Simple ERC20 Token example, with mintable token creation
* @dev Issue: * https://github.com/OpenZeppelin/zeppelin-solidity/issues/120
* Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
*/
contract MintableToken is StandardToken, Ownable {
event Mint(address indexed to, uint256 amount);
event MintFinished();
bool public mintingFinished = false;
modifier canMint() {
require(!mintingFinished);
_;
}
/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
totalSupply = totalSupply.add(_amount);
balances[_to] = balances[_to].add(_amount);
emit Mint(_to, _amount);
emit Transfer(address(0), _to, _amount);
return true;
}
/**
* @dev Function to stop minting new tokens.
* @return True if the operation was successful.
*/
function finishMinting() onlyOwner canMint public returns (bool) {
mintingFinished = true;
emit MintFinished();
return true;
}
}
contract DeveloperToken is MintableToken {
string public constant name = "DeveloperToken";
string public constant symbol = "DEV";
uint256 public constant decimals = 18;
}
contract DeveloperCrowdsale is Ownable {
using SafeMath for uint256;
// 2018-05-29 00:00:00 GMT - start time for private sale
uint256 private constant privatesaleStartTime = 1527552000;
// 2018-05-31 23:59:59 GMT - end time for private sale
uint256 private constant privatesaleEndTime = 1527811199;
// 2018-07-20 00:00:00 GMT - start time for pre sale
uint256 private constant presaleStartTime = 1532044800;
// 2018-08-20 23:59:59 GMT - end time for pre sale
uint256 private constant presaleEndTime = 1534809599;
// 2018-12-02 00:00:00 GMT - start time for main sale
uint256 private constant mainsaleStartTime = 1543708800;
// 2019-01-15 23:59:59 GMT - end time for main sale
uint256 private constant mainsaleEndTime = 1516060799;
// ============= Token Distribution ================
uint256 public maxTokens = 700000000 * 1 ether;
uint256 public totalTokensForSale = 49000000 * 1 ether;
uint256 public tokensForTeam = 10500000 * 1 ether;
uint256 public tokensForReserve = 7000000 * 1 ether;
uint256 public tokensForBounty = 2100000 * 1 ether;
uint256 public tokenForPartnership = 1400000 * 1 ether;
// The token being sold
MintableToken public token;
// address where funds are collected
address public wallet;
// how many token units a buyer gets per wei
uint256 public rate;
// amount of raised money in wei
uint256 public PrivatesaleWeiRaised;
uint256 public PresaleWeiRaised;
uint256 public mainsaleWeiRaised;
// ===== Cap & Goal Management =====
uint256 public privatesaleCap;
uint256 public privatesaleGoal;
uint256 public presaleCap;
uint256 public presaleGoal;
uint256 public mainsaleCap;
uint256 public mainsaleGoal;
/**
* event for token purchase logging
* @param purchaser who paid for the tokens
* @param beneficiary who got the tokens
* @param value weis paid for purchase
* @param amount amount of tokens purchased
*/
event TokenPurchase(
address indexed purchaser,
address indexed beneficiary,
uint256 value,
uint256 amount
);
// ===== Constructor =====
function DeveloperCrowdsale() public {
token = createTokenContract();
rate = 20000;
wallet = msg.sender;
privatesaleCap = 500 * 1 ether;
privatesaleGoal = 200 * 1 ether;
presaleCap = 2000 * 1 ether;
presaleGoal = 700 * 1 ether;
mainsaleCap = 7000 * 1 ether;
mainsaleGoal = 3000 * 1 ether;
}
// creates the token to be sold.
function createTokenContract() internal returns(MintableToken) {
return new DeveloperToken();
}
// ====================== Price Management =================
function setPrice() public onlyOwner {
if (isPrivatesalePeriod()) {
setCurrentRate(20000);
} else if (isPresalePeriod()) {
setCurrentRate(12500);
} else if (isMainsalePeriod()) {
setCurrentRate(5000);
}
}
// Change the current rate
function setCurrentRate(uint256 _rate) private onlyOwner {
rate = _rate;
}
// ====== Token Purchase ===============
function () external payable {
uint256 tokensThatWillBeMintedAfterPurchase = msg.value.mul(rate);
require(token.totalSupply() + tokensThatWillBeMintedAfterPurchase < totalTokensForSale);
buyTokens(msg.sender);
}
function buyTokens(address _beneficiary) public payable {
require(msg.sender != address(0));
require(validPurchase());
uint256 weiAmount = msg.value;
// calculate token amount to be created
uint256 tokens = _getTokenAmount(weiAmount);
// update state
if (isPrivatesalePeriod()) {
PrivatesaleWeiRaised = PrivatesaleWeiRaised.add(weiAmount);
} else if (isPresalePeriod()) {
PresaleWeiRaised = PresaleWeiRaised.add(weiAmount);
} else if (isMainsalePeriod()) {
mainsaleWeiRaised = mainsaleWeiRaised.add(weiAmount);
}
emit TokenPurchase(msg.sender, _beneficiary, weiAmount, tokens);
token.mint(_beneficiary, tokens);
_forwardFunds();
}
function _getTokenAmount(uint256 _weiAmount) internal view returns(uint256) {
return _weiAmount.mul(rate);
}
function _forwardFunds() internal {
wallet.transfer(msg.value);
}
function isPrivatesalePeriod() public view returns (bool) {
if (now >= privatesaleStartTime && now < privatesaleEndTime) {
return true;
}
return false;
}
function isPresalePeriod() public view returns(bool) {
if (now >= presaleStartTime && now < presaleEndTime) {
return true;
}
return false;
}
function isMainsalePeriod() public view returns(bool) {
if (now >= mainsaleStartTime && now < mainsaleEndTime) {
return true;
}
return false;
}
// Finish: Mint Extra Tokens as needed before finalizing the Crowdsale.
function finish(
address _teamFund,
address _reserveFund,
address _bountyFund,
address _partnershipFund
) public onlyOwner {
require(_teamFund != address(0));
require(_reserveFund != address(0));
require(_bountyFund != address(0));
require(_partnershipFund != address(0));
require(now < mainsaleEndTime);
uint256 alreadyMinted = token.totalSupply();
require(alreadyMinted < maxTokens);
uint256 unsoldTokens = totalTokensForSale.sub(alreadyMinted);
if (unsoldTokens > 0) {
tokensForReserve = tokensForReserve.add(unsoldTokens);
}
token.mint(_teamFund, tokensForTeam);
token.mint(_reserveFund, tokensForReserve);
token.mint(_bountyFund, tokensForBounty);
token.mint(_partnershipFund, tokenForPartnership);
token.finishMinting();
}
// @return true if the transaction can buy tokens
function validPurchase() internal view returns (bool) {
bool withinCap;
if (isPrivatesalePeriod()) {
withinCap = PrivatesaleWeiRaised.add(msg.value) <= privatesaleCap;
} else if (isPresalePeriod()) {
withinCap = PresaleWeiRaised.add(msg.value) <= presaleCap;
} else if (isMainsalePeriod()) {
withinCap = mainsaleWeiRaised.add(msg.value) <= mainsaleCap;
}
bool withinPeriod = isPrivatesalePeriod() || isPresalePeriod() || isMainsalePeriod();
bool minimumContribution = msg.value >= 0.5 ether;
return withinPeriod && minimumContribution && withinCap;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment