Skip to content

Instantly share code, notes, and snippets.

@himanshuchawla009
Last active May 19, 2018 15:53
Show Gist options
  • Save himanshuchawla009/07c797301b031fa5f88a5139219e16ad to your computer and use it in GitHub Desktop.
Save himanshuchawla009/07c797301b031fa5f88a5139219e16ad to your computer and use it in GitHub Desktop.
pragma solidity 0.4.21;
contract Ownable {
address public owner;
address public creater;
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(address _owner) public {
creater = msg.sender;
if (_owner != 0) {
owner = _owner;
}
else {
owner = creater;
}
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
modifier isCreator() {
require(msg.sender == creater);
_;
}
/**
* @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); // solhint-disable-line
owner = newOwner;
}
}
library SafeMath {
// it is recommended to define functions which can neither read the state of blockchain nor write in it as pure instead of constant
/**
* @dev Multiplies two numbers, throws on overflow.
*/
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;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
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 a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract IdapToken {
function transfer (address, uint) public pure { }
function burn (uint256) public pure { }
function finalize() public pure { }
function transferOwnership (address) public pure { }
}
contract CrowdSale is Ownable {
using SafeMath for uint256;
// The token being sold
IdapToken public tokenReward;
//Begin: state variables
enum State { fundraising, success, failed, paused, closed }
struct Contributor {
address contriAddress;
uint amount;
uint tokens;
}
mapping(address => Contributor) private contributors;
State public state = State.fundraising;
string public version = "1.0";
mapping (address => bool) public whitelistedContributors;// adreess vs state mapping (1 for exists , zero default);
uint public softCap; //minimum funds in wei to be raised to make ico successful
uint public hardCap; // maximum funds in wei to be raised
uint public totalRaisedInWei; //total funds raises in wei
uint public rateIco; // number of tokens per wei in ico stage
uint public firstBlockChange;
uint public secondBlockChange;
uint public thirdBlockChange;
uint public tokensPerTranche;
uint public fundingStartBlock; //start block of funding
uint public fundingEndBlock;
uint public minimumPricePreIcoInWei; // minimum price for pre ico investers in ether
uint public minimumPriceIcoInWei; // minimum price for normal ico investers in ether
uint public maxPriceInWei; // maximum price in wei in one transaction
uint public tokensDistributed = 0; // Number of tokens distributed
bool private lockTransfer = false;
//End: state variables
modifier inState(State _state) {
require(_state == state);
_;
}
modifier isMinimumPrice() {
if (block.number < thirdBlockChange && block.number >= fundingStartBlock) {
require(msg.value >= minimumPricePreIcoInWei);
} else if (block.number >= thirdBlockChange && block.number <= fundingEndBlock) {
require(msg.value >= minimumPriceIcoInWei);
}
require(msg.value <= maxPriceInWei);
_;
}
modifier isIcoOpen() {
require(block.number >= fundingStartBlock);
require(block.number <= fundingEndBlock);
require(totalRaisedInWei <= hardCap);
_;
}
modifier isEndOfLifeCycle() {
require((state == State.closed || state == State.failed));
_;
}
modifier isIcoFinished() {
require(totalRaisedInWei >= hardCap || block.number > fundingEndBlock || state == State.success);
_;
}
//End: modifiers
//Begin: constructor
function CrowdSale(
uint _softCap,
uint _hardCap,
uint _rateIco,
uint _startBlock,
uint _firstBlockChange,
uint _secondBlockChange,
uint _thirdBlockChange,
uint _durationInHours,
uint _tokensPerTranche,
uint _averageBlockTime,
uint _minimumPreIcoPrice,
uint _minIcoPrice,
IdapToken _tokenAddress,
uint _maxPrice,
address _fundWallet
) public Ownable(_fundWallet) {
require(_softCap > 0 && _hardCap > 0 && _hardCap > _softCap);
require(_rateIco > 0);
require(_startBlock > 0);
require(_durationInHours > 0);
require(_firstBlockChange > _startBlock && _firstBlockChange < _secondBlockChange);
require(_secondBlockChange < _thirdBlockChange);
require(_averageBlockTime > 0);
require(_minimumPreIcoPrice > 0);
require(_minIcoPrice > 0);
require(_maxPrice > 0);
require(_tokenAddress != address(0));
require(_tokensPerTranche > 0);
creater = msg.sender;
softCap = _softCap * 1 ether;
hardCap = _hardCap * 1 ether;
tokensPerTranche = _tokensPerTranche;
rateIco = _rateIco;
fundingStartBlock = _startBlock;
fundingEndBlock = _startBlock.add(_durationInHours.mul((3600 / _averageBlockTime)));
firstBlockChange = _firstBlockChange;
secondBlockChange = _secondBlockChange;
thirdBlockChange = _thirdBlockChange;
minimumPriceIcoInWei = _minIcoPrice * 1 ether;
minimumPricePreIcoInWei = _minimumPreIcoPrice * 1 ether;
maxPriceInWei = _maxPrice * 1 ether;
tokenReward = IdapToken(_tokenAddress);
}
//End: constructor
function buyTokens(address _beneficiary) public inState(State.fundraising) isMinimumPrice isIcoOpen payable {
require(_beneficiary != 0x0);
require(whitelistedContributors[_beneficiary] == true);
require(!lockTransfer);
uint rate = getCurrentRate();
uint tokenAmount;
uint receivedWei = totalRaisedInWei.add(msg.value);
if (receivedWei > hardCap) {
lockTransfer = true;
totalRaisedInWei = totalRaisedInWei.add((hardCap.sub(totalRaisedInWei)));
// // Calculate how many tokens (in units of Wei) should be awarded on this transaction
tokenAmount = rate.mul((hardCap.sub(totalRaisedInWei)));
tokensDistributed = tokensDistributed.add(tokenAmount);
// Send change extra ether to user.
_beneficiary.transfer(receivedWei.sub(hardCap));
} else {
totalRaisedInWei = totalRaisedInWei.add(msg.value);
tokenAmount = rate.mul(msg.value);
tokensDistributed = tokensDistributed.add(tokenAmount);
}
lockTransfer = false;
contributors[_beneficiary].contriAddress = _beneficiary;
contributors[_beneficiary].amount = msg.value;
contributors[_beneficiary].tokens = tokenAmount;
checkIfFundingSuccessOrFailed();
tokenReward.transfer(_beneficiary, tokenAmount);
}
function refundIfFundingFailed() external inState(State.failed) returns (bool) {
if (contributors[msg.sender].contriAddress == msg.sender && contributors[msg.sender].amount > 0) {
uint refund = contributors[msg.sender].amount;
contributors[msg.sender].amount = 0;
totalRaisedInWei -= refund;
msg.sender.transfer(refund);
return true;
}
return false;
}
function changeIdapTokenOwner(address _newOwner) external onlyOwner {
require(_newOwner != address(0));
tokenReward.transferOwnership(_newOwner);
}
// after ICO only owner can call this
function burnRemainingToken(uint256 _value) external view onlyOwner isIcoFinished {
//@TODO - check balance of address if no value passed
require(_value > 0);
tokenReward.burn(_value);
}
// after ICO only owner can call this
function withdrawRemainingToken(uint256 _value, address tokenAdmin) external view onlyOwner isIcoFinished {
//@TODO - check balance of address if no value passed
require(tokenAdmin != 0x0);
require(_value > 0);
tokenReward.transfer(tokenAdmin, _value);
}
function authorizeKyc(address[] addrs) external onlyOwner returns (bool success) {
//@TODO maximum batch size for uploading
// @TODO amount of gas for a block of code - and will fail if that is exceeded
uint arrayLength = addrs.length;
for (uint x = 0; x < arrayLength; x++) {
whitelistedContributors[addrs[x]] = true;
}
return true;
}
function destroyContract() external onlyOwner isEndOfLifeCycle {
selfdestruct(msg.sender);
}
function() external payable {
buyTokens(msg.sender);
}
/// @dev Pauses the contract
function pause() external onlyOwner inState(State.fundraising) {
// Move the contract to Paused state
state = State.paused;
}
/// @dev Resume the contract
function resume() external onlyOwner inState(State.paused) {
// Move the contract out of the Paused state
state = State.fundraising;
}
function sendFundsToOwner() private inState(State.success) {
state = State.closed;
//@TODO: manual testing
owner.transfer(address(this).balance);
}
function getCurrentRate() private constant returns (uint) {
if (block.number < firstBlockChange && block.number > fundingStartBlock) {
return (rateIco.add((rateIco.mul(30)/100)));
}
else if(block.number < secondBlockChange && block.number > firstBlockChange) {
return (rateIco.add((rateIco.mul(20)/100)));
}
else if(block.number < thirdBlockChange && block.number > secondBlockChange) {
return (rateIco.add((rateIco.mul(10)/100)));
}
else if(block.number < fundingEndBlock && block.number > thirdBlockChange) {
return rateIco;
}
}
function checkIfFundingSuccessOrFailed() private {
if (block.number > fundingEndBlock && totalRaisedInWei >= hardCap) {
state = State.success;
sendFundsToOwner();
tokenReward.finalize();
}
else if (block.number > fundingEndBlock && totalRaisedInWei < softCap) {
state = State.failed;
tokenReward.finalize();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment