Created
November 22, 2017 16:06
-
-
Save libracoder/82b52edf45e1e389fc0ea832c4b88307 to your computer and use it in GitHub Desktop.
Crowdsale
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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