Last active
May 19, 2018 15:53
-
-
Save himanshuchawla009/07c797301b031fa5f88a5139219e16ad to your computer and use it in GitHub Desktop.
This file contains hidden or 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.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