pragma solidity ^0.4.24; contract ERC20Basic { function totalSupply() public view returns (uint256); 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); } library SafeMath { function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { if (_a == 0) { return 0; } c = _a * _b; assert(c / _a == _b); return c; } function div(uint256 _a, uint256 _b) internal pure returns (uint256) { return _a / _b; } 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 c) { c = _a + _b; assert(c >= _a); return c; } } contract BasicToken is ERC20Basic { using SafeMath for uint256; mapping(address => uint256) internal balances; uint256 internal totalSupply_; function totalSupply() public view returns (uint256) { return totalSupply_; } function transfer(address _to, uint256 _value) public returns (bool) { require(_value <= balances[msg.sender]); require(_to != address(0)); balances[msg.sender] = balances[msg.sender].sub(_value); balances[_to] = balances[_to].add(_value); emit Transfer(msg.sender, _to, _value); return true; } function balanceOf(address _owner) public view returns (uint256) { return balances[_owner]; } } 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 ); } contract StandardToken is ERC20, BasicToken { mapping(address => mapping(address => uint256)) internal allowed; function transferFrom( address _from, address _to, uint256 _value ) public returns (bool) { require(_value <= balances[_from]); require(_value <= allowed[_from][msg.sender]); require(_to != address(0)); 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; } function approve(address _spender, uint256 _value) public returns (bool) { allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } function allowance( address _owner, address _spender ) public view returns (uint256) { return allowed[_owner][_spender]; } function increaseApproval( address _spender, uint256 _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; } function decreaseApproval( address _spender, uint256 _subtractedValue ) public returns (bool) { uint256 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; } } contract Ownable { address public owner; event OwnershipRenounced(address indexed previousOwner); event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); constructor() public { owner = msg.sender; } modifier onlyOwner() { require(msg.sender == owner); _; } function renounceOwnership() public onlyOwner { emit OwnershipRenounced(owner); owner = address(0); } function transferOwnership(address _newOwner) public onlyOwner { _transferOwnership(_newOwner); } function _transferOwnership(address _newOwner) internal { require(_newOwner != address(0)); emit OwnershipTransferred(owner, _newOwner); owner = _newOwner; } } contract MintableToken is StandardToken, Ownable { event Mint(address indexed to, uint256 amount); event MintFinished(); bool public mintingFinished = false; modifier canMint() { require(!mintingFinished); _; } modifier hasMintPermission() { require(msg.sender == owner); _; } function mint( address _to, uint256 _amount ) public hasMintPermission canMint returns (bool) { totalSupply_ = totalSupply_.add(_amount); balances[_to] = balances[_to].add(_amount); emit Mint(_to, _amount); emit Transfer(address(0), _to, _amount); return true; } function finishMinting() public onlyOwner canMint returns (bool) { mintingFinished = true; emit MintFinished(); return true; } } contract DetailedERC20 is ERC20 { string public name; string public symbol; uint8 public decimals; constructor(string _name, string _symbol, uint8 _decimals) public { name = _name; symbol = _symbol; decimals = _decimals; } } contract WAS_Token is MintableToken, DetailedERC20 { uint256 public totalSupplyLimit = 260260676; constructor() DetailedERC20("Wasi", "WAS", 0) public { } function burnUnsoldTokens() public onlyOwner { balances[owner] = 0; } } contract WAS_CrowdsaleReservations { using SafeMath for uint256; uint256 public reserveTokensTeamPercent = 5; // 13013033 tokens uint256 public reservedTokensTeam; uint256 public tokensCrowdsalePurchased; uint256 public reservedTokensCrowdsalePurchase; constructor(uint256 _totalSupply) public { calculateReservations(_totalSupply); } function calculateReservations(uint256 _totalSupply) private { reservedTokensTeam = _totalSupply.mul(reserveTokensTeamPercent).div(100); reservedTokensCrowdsalePurchase = 50 * (10 ** 6); // 50m } } library SafeERC20 { function safeTransfer( ERC20Basic _token, address _to, uint256 _value ) internal { require(_token.transfer(_to, _value)); } function safeTransferFrom( ERC20 _token, address _from, address _to, uint256 _value ) internal { require(_token.transferFrom(_from, _to, _value)); } function safeApprove( ERC20 _token, address _spender, uint256 _value ) internal { require(_token.approve(_spender, _value)); } } contract Crowdsale { using SafeMath for uint256; using SafeERC20 for ERC20; ERC20 public token; address public wallet; uint256 public rate; uint256 public weiRaised; event TokenPurchase( address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount ); constructor(uint256 _rate, address _wallet, ERC20 _token) public { require(_rate > 0); require(_wallet != address(0)); require(_token != address(0)); rate = _rate; wallet = _wallet; token = _token; } function() external payable { buyTokens(msg.sender); } function buyTokens(address _beneficiary) public payable { uint256 weiAmount = msg.value; _preValidatePurchase(_beneficiary, weiAmount); uint256 tokens = _getTokenAmount(weiAmount); weiRaised = weiRaised.add(weiAmount); _processPurchase(_beneficiary, tokens); emit TokenPurchase( msg.sender, _beneficiary, weiAmount, tokens ); _updatePurchasingState(_beneficiary, weiAmount); _forwardFunds(); _postValidatePurchase(_beneficiary, weiAmount); } function _preValidatePurchase( address _beneficiary, uint256 _weiAmount ) internal { require(_beneficiary != address(0)); require(_weiAmount != 0); } function _postValidatePurchase( address _beneficiary, uint256 _weiAmount ) internal { } function _deliverTokens( address _beneficiary, uint256 _tokenAmount ) internal { token.safeTransfer(_beneficiary, _tokenAmount); } function _processPurchase( address _beneficiary, uint256 _tokenAmount ) internal { _deliverTokens(_beneficiary, _tokenAmount); } function _updatePurchasingState( address _beneficiary, uint256 _weiAmount ) internal { } function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) { return _weiAmount.mul(rate); } function _forwardFunds() internal { wallet.transfer(msg.value); } } contract TimedCrowdsale is Crowdsale { using SafeMath for uint256; uint256 public openingTime; uint256 public closingTime; modifier onlyWhileOpen { require(block.timestamp >= openingTime && block.timestamp <= closingTime); _; } constructor(uint256 _openingTime, uint256 _closingTime) public { require(_openingTime >= block.timestamp); require(_closingTime >= _openingTime); openingTime = _openingTime; closingTime = _closingTime; } function hasClosed() public view returns (bool) { return block.timestamp > closingTime; } function _preValidatePurchase( address _beneficiary, uint256 _weiAmount ) internal onlyWhileOpen { super._preValidatePurchase(_beneficiary, _weiAmount); } } contract FinalizableCrowdsale is Ownable, TimedCrowdsale { using SafeMath for uint256; bool public isFinalized = false; event Finalized(); function finalize() public onlyOwner { require(!isFinalized); require(hasClosed()); finalization(); emit Finalized(); isFinalized = true; } function finalization() internal { } } contract WAS_Crowdsale_Stages is FinalizableCrowdsale, WAS_CrowdsaleReservations { uint256[] rateETH; uint256[] openingTimings; uint256[] closingTimings; uint256[] stagePurchaseTokensMinimum; modifier onlyWhileOpen { bool stageRunning; uint256 stageIdx; (stageRunning, stageIdx) = currentStage(); require(stageRunning, "no stage is currently running"); _; } constructor(uint256[] _rateETH, uint256[] _openingTimings, uint256[] _closingTimings) TimedCrowdsale(_openingTimings[0], _closingTimings[_closingTimings.length - 1]) public { validateRates(_rateETH); validateOpeningAndClosingTimings(_openingTimings, _closingTimings); rateETH = _rateETH; openingTimings = _openingTimings; closingTimings = _closingTimings; stagePurchaseTokensMinimum = [0, 100]; } function hasOpened() public view returns (bool) { return now >= openingTime; } function currentRateETH() public view returns (uint256) { bool stageRunning; uint256 stageIdx; (stageRunning, stageIdx) = currentStage(); require(stageRunning, "no stage is currently running"); return rateETH[stageIdx]; } function currentDiscount(uint256 _tokenPurchasedAmount) public view returns (uint256) { bool stageRunning; uint256 stageIdx; (stageRunning, stageIdx) = currentStage(); require(stageRunning, "no stage is currently running"); return discountPercentForStage(stageIdx, _tokenPurchasedAmount); } function currentStage() public view returns (bool, uint256) { for (uint256 i = 0; i < closingTimings.length; i ++) { if (block.timestamp <= closingTimings[i] && block.timestamp >= openingTimings[i]) { return (true, i); } } return (false, 0); } function updateStageRateETH(uint256 _stage, uint256 _rateETH) public onlyOwner { rateETH[_stage] = _rateETH; } function updateOpeningAndClosingTimings(uint256[] _openingTimings, uint256[] _closingTimings) public onlyOwner { validateOpeningAndClosingTimings(_openingTimings, _closingTimings); openingTimings = _openingTimings; closingTimings = _closingTimings; } function validateRates(uint256[] _rateETH) private pure { for (uint256 i = 0; i < _rateETH.length; i ++) { require(_rateETH[i] > 0, "rate must be > 0"); } } function validateOpeningAndClosingTimings(uint256[] _openingTimings, uint256[] _closingTimings) private view { require(_openingTimings.length == _closingTimings.length, "timings length differs"); require(_openingTimings[0] > block.timestamp, "should open in future"); for (uint256 i = 0; i < _openingTimings.length; i ++) { require(_closingTimings[i] > _openingTimings[i], "closing time of stage must be > opening time of same stage"); if (i > 0) { require(_openingTimings[i] > _openingTimings[i - 1], "opening time must be > than previous opening time"); } } } function discountPercentForStage(uint256 _stage, uint256 _tokenPurchasedAmount) private pure returns (uint256) { if (_stage == 0) { return 30; } else if (_stage == 1) { if (_tokenPurchasedAmount >= 15000) { return 10; } else if (_tokenPurchasedAmount >= 10000) { return 7; } else if (_tokenPurchasedAmount >= 5000) { return 5; } } return 0; } } contract Pausable is Ownable { event Pause(); event Unpause(); bool public paused = false; modifier whenNotPaused() { require(!paused); _; } modifier whenPaused() { require(paused); _; } function pause() public onlyOwner whenNotPaused { paused = true; emit Pause(); } function unpause() public onlyOwner whenPaused { paused = false; emit Unpause(); } } library Roles { struct Role { mapping(address => bool) bearer; } function add(Role storage _role, address _addr) internal { _role.bearer[_addr] = true; } function remove(Role storage _role, address _addr) internal { _role.bearer[_addr] = false; } function check(Role storage _role, address _addr) internal view { require(has(_role, _addr)); } function has(Role storage _role, address _addr) internal view returns (bool) { return _role.bearer[_addr]; } } contract RBAC { using Roles for Roles.Role; mapping(string => Roles.Role) private roles; event RoleAdded(address indexed operator, string role); event RoleRemoved(address indexed operator, string role); function checkRole(address _operator, string _role) public view { roles[_role].check(_operator); } function hasRole(address _operator, string _role) public view returns (bool) { return roles[_role].has(_operator); } function addRole(address _operator, string _role) internal { roles[_role].add(_operator); emit RoleAdded(_operator, _role); } function removeRole(address _operator, string _role) internal { roles[_role].remove(_operator); emit RoleRemoved(_operator, _role); } modifier onlyRole(string _role) { checkRole(msg.sender, _role); _; } } contract Whitelist is Ownable, RBAC { string public constant ROLE_WHITELISTED = "whitelist"; modifier onlyIfWhitelisted(address _operator) { checkRole(_operator, ROLE_WHITELISTED); _; } function addAddressToWhitelist(address _operator) public onlyOwner { addRole(_operator, ROLE_WHITELISTED); } function whitelist(address _operator) public view returns (bool) { return hasRole(_operator, ROLE_WHITELISTED); } function addAddressesToWhitelist(address[] _operators) public onlyOwner { for (uint256 i = 0; i < _operators.length; i++) { addAddressToWhitelist(_operators[i]); } } function removeAddressFromWhitelist(address _operator) public onlyOwner { removeRole(_operator, ROLE_WHITELISTED); } function removeAddressesFromWhitelist(address[] _operators) public onlyOwner { for (uint256 i = 0; i < _operators.length; i++) { removeAddressFromWhitelist(_operators[i]); } } } contract WhitelistedCrowdsale is Whitelist, Crowdsale { function _preValidatePurchase( address _beneficiary, uint256 _weiAmount ) internal onlyIfWhitelisted(_beneficiary) { super._preValidatePurchase(_beneficiary, _weiAmount); } } contract Destructible is Ownable { function destroy() public onlyOwner { selfdestruct(owner); } function destroyAndSend(address _recipient) public onlyOwner { selfdestruct(_recipient); } } contract WAS_Crowdsale is WhitelistedCrowdsale, Destructible, Pausable, WAS_Crowdsale_Stages { WAS_Token token; constructor(address _wallet, ERC20 _token, uint256[] _rateETH, uint256[] _openingTimings, uint256[] _closingTimings) Crowdsale(1, _wallet, _token) WAS_Crowdsale_Stages(_rateETH, _openingTimings, _closingTimings) WAS_CrowdsaleReservations(WAS_Token(_token).totalSupplyLimit()) public { require(_token != address(0), "token address cannt be 0"); token = WAS_Token(_token); } function mintTotalSupplyAndTeam(address _teamAddress) public onlyOwner { require(_teamAddress != address(0), "team address can not be 0"); require(reservedTokensTeam > 0, "team tokens can not be 0"); token.mint(_teamAddress, reservedTokensTeam); uint256 purchaseTokens = token.totalSupplyLimit().sub(reservedTokensTeam); token.mint(address(this), purchaseTokens); token.finishMinting(); } function manualTransfer(address _to, uint256 _tokenAmount) public onlyOwner { bool stageRunning; uint256 stageIdx; (stageRunning, stageIdx) = currentStage(); require(stageRunning, "no stage is currently running"); require(stageIdx == 0, "manual transfer allowed during first stage only"); require(tokensCrowdsalePurchased.add(_tokenAmount) <= reservedTokensCrowdsalePurchase, "not enough tokens to manually transfer"); tokensCrowdsalePurchased = tokensCrowdsalePurchased.add(_tokenAmount); token.transfer(_to, _tokenAmount); } function destroy() public onlyOwner { require(hasClosed(), "crowdsale must be closed"); require(isFinalized, "crowdsale must be finalized"); selfdestruct(owner); } function destroyAndSend(address _recipient) public onlyOwner { require(hasClosed(), "crowdsale must be closed"); require(isFinalized, "crowdsale must be finalized"); selfdestruct(_recipient); } function finalization() internal { uint256 unpurchasedTokens = token.balanceOf(address(this)); token.transfer(owner, unpurchasedTokens); super.finalization(); } function _preValidatePurchase( address _beneficiary, uint256 _weiAmount ) internal whenNotPaused() onlyWhileOpen() { super._preValidatePurchase(_beneficiary, _weiAmount); } function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) { uint256 rateETH = currentRateETH(); uint256 tokens = _weiAmount.mul(rateETH).div(uint256(10 ** 18)); uint256 discount = currentDiscount(tokens); if (discount > 0) { tokens = tokens.add(tokens.mul(discount).div(100)); } return tokens; } function _processPurchase( address _beneficiary, uint256 _tokenAmount ) internal { bool stageRunning; uint256 stageIdx; (stageRunning, stageIdx) = currentStage(); require(stageRunning, "no stage is currently running"); require(_tokenAmount >= stagePurchaseTokensMinimum[stageIdx], "token amount is less than minimum for stage"); require(tokensCrowdsalePurchased.add(_tokenAmount) <= reservedTokensCrowdsalePurchase, "not enough tokens to purchase"); tokensCrowdsalePurchased = tokensCrowdsalePurchased.add(_tokenAmount); super._processPurchase(_beneficiary, _tokenAmount); } }