Skip to content

Instantly share code, notes, and snippets.

@libracoder
Created November 22, 2017 16:06
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 libracoder/82b52edf45e1e389fc0ea832c4b88307 to your computer and use it in GitHub Desktop.
Save libracoder/82b52edf45e1e389fc0ea832c4b88307 to your computer and use it in GitHub Desktop.
Crowdsale
pragma solidity ^0.4.18;
/// @title Math operations with safety checks
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a * b;
assert(a == 0 || 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;
}
function max64(uint64 a, uint64 b) internal pure returns (uint64) {
return a >= b ? a : b;
}
function min64(uint64 a, uint64 b) internal pure returns (uint64) {
return a < b ? a : b;
}
function max256(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
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) onlyOwner public {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
contract BasicToken {
using SafeMath for uint;
uint public totalTokenSupply;
mapping (address => uint) balances;
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
/*****
* @dev Tranfer the token balance to a specified address
* @param _to The address to transfer to
* @param _value The value to be transferred
*/
function _transfer(address _from, address _to, uint _value) public {
// Prevent transfer to 0x0 address. Use burn() instead
require(_to != 0x0);
// Check if the sender has enough
require(balances[_from] >= _value);
// Check for overflows
require(balances[_to] + _value > balances[_to]);
// Subtract from the sender
balances[_from] -= _value;
// Add the same to the recipient
balances[_to] += _value;
Transfer(_from, _to, _value);
}
function transfer(address _to, uint _value) public returns (bool success) {
_transfer(msg.sender, _to, _value);
return true;
}
/*****
* @dev Gets the balances of the specified address
* @param _owner The address to query the balance of
* @return An uint representing the amount owned by the passed address
*/
function balanceOf(address _owner) public constant returns (uint balance){
return balances[_owner];
}
/*****
* @dev Gets the totalSupply of the tokens.
*/
function totalSupply() public constant returns (uint totalSupply) {
totalSupply = totalTokenSupply;
}
}
contract Token is BasicToken {
using SafeMath for uint256;
string public name= "DFX COIN"; // Defines the name of the token.
string public symbol = "DFX"; // Defines the symbol of the token.
uint256 public decimals=18; // Number of decimal places for the token.
uint256 public totalSupply; // Total Supply of the coin
uint256 public _initialSupply=1000;
// Owner of account approves the transfer of an amount to another account
mapping (address => mapping (address => uint256)) allowed;
function Token() public {
totalSupply = _initialSupply * 10 ** uint256(decimals);
}
// Allow _spender to withdraw from your account, multiple times, up to the _value amount.
// If this function is called again it overwrites the current allowance with _value.
function approve(address _spender, uint256 _amount) returns (bool success) {
allowed[msg.sender][_spender] = _amount;
Approval(msg.sender, _spender, _amount);
return true;
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
/*****
* @dev Transfer the amount of money invested by the investor to his balance
* Also, keeps track of at what rate did they buy the token, keeps track of
* different rates of tokens at PreSale and ICO
* @param _recipient address The address of the investor
* @param _value uint256 The number of the tokens bought
* @param _ratePerETH uint256 The rate at which it was bought, different for Pre Sale/ICO
* @return bool Returns true, if all goes as expected
*/
function transferTokens(address _recipient, uint256 _value, uint256 _ratePerETH) public returns (bool) {
uint256 finalAmount = _value.mul(_ratePerETH);
if(transfer( _recipient, finalAmount)){
return true;
}
return false;
}
// @transfer token between addresses
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(balances[_from] >= _value
&& allowed[_from][msg.sender] >= _value
&& _value > 0
&& balances[_to] + _value > balances[_to]);
// Check allowance
allowed[_from][msg.sender] -= _value;
balances[_to] += _value;
Transfer(_from, _to, _value);
return true;
}
/*****
* @dev Used to remove the balance, when asking for refund
* @param _recipient address The beneficiary of the refund
* @return bool Returns true, if successful
*/
function refundedAmount(address _recipient) public returns (bool) {
require(balances[_recipient] != 0);
balances[_recipient] = 0;
return true;
}
}
/*****
* @title The Crowd Sale Contract
*/
contract TokenSale is Ownable {
using SafeMath for uint256;
// Instance of the Real Token
Token public token;
// Received funds are transferred to the beneficiary
address public beneficiary;
// Number of Tokens/ETH in PreSale
uint256 public tokenPerEthPreSale;
// Number of Tokens/ETH in ICO
uint256 public tokenPerEthICO;
// Start Timestamp of Pre Sale
uint256 public presaleStartTimestamp;
// End Timestamp of Pre Sale
uint256 public presaleEndTimestamp;
// Start Timestamp for the ICO
uint256 public icoStartTimestamp;
// End Timestamp for the ICO
uint256 public icoEndTimestamp;
// Amount of tokens available for sale in Pre Sale Period
uint256 public presaleTokenLimit;
// Amount of tokens available for sale in ICO Period
uint256 public icoTokenLimit;
// Total Tokens Sold in Pre Sale Period
uint256 public presaleTokenRaised;
// Total Tokens Sold in ICO Period
uint256 public icoTokenRaised;
// Max Cap for Pre Sale
uint256 public presaleMaxEthCap;
// Min Cap for ICO
uint256 public icoMinEthCap;
// Max Cap for ICO
uint256 public icoMaxEthCap;
// Different number of Investors
uint256 public investorCount;
/*****
* State machine
* - Unknown: Default Initial State of the Contract
* - Preparing: All contract initialization calls
* - PreSale: We are into PreSale Period
* - ICO: The real Sale of Tokens, after Pre Sale
* - Success: Minimum funding goal reached
* - Failure: Minimum funding goal not reached
* - Finalized: The ICO has been concluded
* - Refunding: Refunds are loaded on the contract for reclaim.
*/
enum State{Unknown, Preparing, PreSale, ICO, Success, Failure, PresaleFinalized, ICOFinalized}
State public crowdSaleState;
/*****
* @dev Modifier to check that amount transferred is not 0
*/
modifier nonZero() {
require(msg.value != 0);
_;
}
/*****
* @dev The constructor function to initialize the token related properties
* @param _token address Specifies the address of the Token Contract
* @param _presaleRate uint256 Specifies the amount of tokens that can be bought per ETH during Pre Sale
* @param _icoRate uint256 Specifies the amount of tokens that can be bought per ETH during ICO
* @param _presaleStartTime uint256 Specifies the Start Date of the Pre Sale
* @param _presaleDays uint256 Specifies the duration of the Pre Sale
* @param _icoStartTime uint256 Specifies the Start Date for the ICO
* @param _icoDays uint256 Specifies the duration of the ICO
* @param _maxPreSaleEthCap uint256 Maximum amount of ETHs to raise in Pre Sale
* @param _minICOEthCap uint256 Minimum amount of ETHs to raise in ICO
* @param _maxICOEthCap uint256 Maximum amount of ETHs to raise in ICO
*/
address _token = 0x7332b9f08144ed2b979f0d28780f4a00d4402d15;
uint256 _presaleRate=300;
uint256 _icoRate=500;
uint256 _presaleStartTime=1511301043;
uint256 _presaleDays=20;
uint256 _icoStartTime=1512301043;
uint256 _icoDays=20;
uint256 _maxPreSaleEthCap=300000;
uint256 _minICOEthCap=290000;
uint256 _maxICOEthCap=200000;
function TokenSale() public {
require(_token != address(0));
require(_presaleRate != 0);
require(_icoRate != 0);
require(_presaleStartTime > now);
require(_icoStartTime > _presaleStartTime);
require(_minICOEthCap <= _maxICOEthCap);
token = Token(_token);
tokenPerEthPreSale = _presaleRate;
tokenPerEthICO = _icoRate;
presaleStartTimestamp = _presaleStartTime;
presaleEndTimestamp = _presaleStartTime + _presaleDays * 1 days;
require(_icoStartTime > presaleEndTimestamp);
icoStartTimestamp = _icoStartTime;
icoEndTimestamp = _icoStartTime + _icoDays * 1 days;
presaleMaxEthCap = _maxPreSaleEthCap;
icoMinEthCap = _minICOEthCap;
icoMaxEthCap = _maxICOEthCap;
presaleTokenLimit = _maxPreSaleEthCap.div(_presaleRate);
icoTokenLimit = _maxICOEthCap.div(_icoRate);
assert(token.totalSupply() >= presaleTokenLimit.add(icoTokenLimit));
crowdSaleState = State.Preparing;
}
/*****
* @dev Fallback Function to buy the tokens
*/
function() nonZero payable public {
if (isPreSalePeriod()) {
if (crowdSaleState == State.Preparing) {
crowdSaleState = State.PreSale;
}
buyTokens(msg.sender, msg.value);
}
else if (isICOPeriod()) {
if (crowdSaleState == State.PresaleFinalized) {
crowdSaleState = State.ICO;
}
buyTokens(msg.sender, msg.value);
}
else {
revert();
}
}
/*****
* @dev Internal function to execute the token transfer to the Recipient
* @param _recipient address The address who will receives the tokens
* @param _value uint256 The amount invested by the recipient
* @return success bool Returns true if executed successfully
*/
function buyTokens(address _recipient, uint256 _value) internal returns (bool success) {
uint256 boughtTokens = calculateTokens(_value);
require(boughtTokens != 0);
if (token.balanceOf(_recipient) == 0) {
investorCount++;
}
if (isCrowdSaleStatePreSale()) {
token.transferTokens(_recipient, boughtTokens, tokenPerEthPreSale);
presaleTokenRaised = presaleTokenRaised.add(_value);
return true;
}
else if (isCrowdSaleStateICO()) {
token.transferTokens(_recipient, boughtTokens, tokenPerEthICO);
icoTokenRaised = icoTokenRaised.add(_value);
return true;
}
}
/*****
* @dev Calculates the number of tokens that can be bought for the amount of WEIs transferred
* @param _amount uint256 The amount of money invested by the investor
* @return tokens uint256 The number of tokens
*/
function calculateTokens(uint256 _amount) returns (uint256 tokens){
if (isCrowdSaleStatePreSale()) {
tokens = _amount.mul(tokenPerEthPreSale);
}
else if (isCrowdSaleStateICO()) {
tokens = _amount.mul(tokenPerEthICO);
}
else {
tokens = 0;
}
}
/*****
* @dev Check the state of the Contract, if in Pre Sale
* @return bool Return true if the contract is in Pre Sale
*/
function isCrowdSaleStatePreSale() public constant returns (bool) {
return crowdSaleState == State.PreSale;
}
/*****
* @dev Check the state of the Contract, if in ICO
* @return bool Return true if the contract is in ICO
*/
function isCrowdSaleStateICO() public constant returns (bool) {
return crowdSaleState == State.ICO;
}
/*****
* @dev Check if the Pre Sale Period is still ON
* @return bool Return true if the contract is in Pre Sale Period
*/
function isPreSalePeriod() public payable returns (bool) {
if (presaleTokenRaised > presaleMaxEthCap || now >= presaleEndTimestamp) {
crowdSaleState = State.PresaleFinalized;
return false;
}
else {
return now > presaleStartTimestamp;
}
}
/*****
* @dev Check if the ICO is in the Sale period or not
* @return bool Return true if the contract is in ICO Period
*/
function isICOPeriod() public payable returns (bool) {
if (icoTokenRaised > icoMaxEthCap || now >= icoEndTimestamp) {
crowdSaleState = State.ICOFinalized;
return false;
}
else {
return now > icoStartTimestamp;
}
}
/*****
* @dev Called by the owner of the contract to close the Sale
*/
function endCrowdSale() onlyOwner {
require(now >= icoEndTimestamp || icoTokenRaised >= icoMaxEthCap);
if (icoTokenRaised >= icoMinEthCap) {
crowdSaleState = State.Success;
beneficiary.transfer(icoTokenRaised);
beneficiary.transfer(presaleTokenRaised);
}
else {
crowdSaleState = State.Failure;
}
}
/*****
* @dev Allow investors to take their mmoney back after a failure in ICO
* @param _recipient address The caller of the function who is looking for refund
* @return bool Return true, if executed successfully
*/
function getRefund(address _recipient) public returns (bool){
require(crowdSaleState == State.Failure);
uint256 amount = token.balanceOf(_recipient);
require(token.refundedAmount(_recipient));
_recipient.transfer(amount);
return true;
}
/*****
* Fetch some statistics about the ICO
*/
/*****
* @dev Fetch the count of different Investors
* @return bool Returns the total number of different investors
*/
function getInvestorCount() public constant returns (uint256) {
return investorCount;
}
/*****
* @dev Fetch the amount raised in Pre Sale
* @return uint256 Returns the amount of money raised in Pre Sale
*/
function getPresaleRaisedAmount() public constant returns (uint256) {
return presaleTokenRaised;
}
/*****
* @dev Fetch the amount raised in ICO
* @return uint256 Returns the amount of money raised in ICO
*/
function getICORaisedAmount() public constant returns (uint256) {
return icoTokenRaised;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment