Skip to content

Instantly share code, notes, and snippets.

@kissarat
Created October 18, 2018 10:15
Show Gist options
  • Select an option

  • Save kissarat/17cb948fd35bb40f643b1772f1073194 to your computer and use it in GitHub Desktop.

Select an option

Save kissarat/17cb948fd35bb40f643b1772f1073194 to your computer and use it in GitHub Desktop.

Revisions

  1. kissarat revised this gist Oct 18, 2018. 1 changed file with 302 additions and 211 deletions.
    513 changes: 302 additions & 211 deletions flattened.sol
    Original file line number Diff line number Diff line change
    @@ -1,115 +1,137 @@
    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) {
    function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
    if (_a == 0) {
    return 0;
    }
    c = _a * _b;
    c = _a * _b;
    assert(c / _a == _b);
    return c;
    }
    function div(uint256 _a, uint256 _b) internal pure returns (uint256) {

    function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
    return _a / _b;
    }
    function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {

    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) {

    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) {
    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) {

    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[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) {

    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);
    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(
    mapping(address => mapping(address => uint256)) internal allowed;

    function transferFrom(
    address _from,
    address _to,
    uint256 _value
    )
    public
    returns (bool)
    public
    returns (bool)
    {
    require(_value <= balances[_from]);
    require(_value <= allowed[_from][msg.sender]);
    require(_to != address(0));
    balances[_from] = balances[_from].sub(_value);
    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) {

    function approve(address _spender, uint256 _value) public returns (bool) {
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    return true;
    }
    function allowance(

    function allowance(
    address _owner,
    address _spender
    )
    public
    view
    returns (uint256)
    )
    public
    view
    returns (uint256)
    {
    return allowed[_owner][_spender];
    }
    function increaseApproval(

    function increaseApproval(
    address _spender,
    uint256 _addedValue
    )
    public
    returns (bool)
    public
    returns (bool)
    {
    allowed[msg.sender][_spender] = (
    allowed[msg.sender][_spender].add(_addedValue));
    allowed[msg.sender][_spender].add(_addedValue));
    emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
    }
    function decreaseApproval(

    function decreaseApproval(
    address _spender,
    uint256 _subtractedValue
    )
    public
    returns (bool)
    public
    returns (bool)
    {
    uint256 oldValue = allowed[msg.sender][_spender];
    if (_subtractedValue >= oldValue) {
    @@ -121,565 +143,634 @@ function decreaseApproval(
    return true;
    }
    }

    contract Ownable {
    address public owner;
    event OwnershipRenounced(address indexed previousOwner);

    event OwnershipRenounced(address indexed previousOwner);
    event OwnershipTransferred(
    address indexed previousOwner,
    address indexed newOwner
    );
    constructor() public {
    constructor() public {
    owner = msg.sender;
    }
    modifier onlyOwner() {
    modifier onlyOwner() {
    require(msg.sender == owner);
    _;
    }
    function renounceOwnership() public onlyOwner {
    function renounceOwnership() public onlyOwner {
    emit OwnershipRenounced(owner);
    owner = address(0);
    }
    function transferOwnership(address _newOwner) public onlyOwner {

    function transferOwnership(address _newOwner) public onlyOwner {
    _transferOwnership(_newOwner);
    }
    function _transferOwnership(address _newOwner) internal {

    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() {

    bool public mintingFinished = false;
    modifier canMint() {
    require(!mintingFinished);
    _;
    }
    modifier hasMintPermission() {
    modifier hasMintPermission() {
    require(msg.sender == owner);
    _;
    }
    function mint(
    function mint(
    address _to,
    uint256 _amount
    )
    public
    hasMintPermission
    canMint
    returns (bool)
    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) {

    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 {
    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;
    }
    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 reserveTokensTeamPercent = 5; // 13013033 tokens
    uint256 public reservedTokensTeam;
    uint256 public tokensCrowdsalePurchased;
    uint256 public tokensCrowdsalePurchased;
    uint256 public reservedTokensCrowdsalePurchase;
    constructor(uint256 _totalSupply) public {
    constructor(uint256 _totalSupply) public {
    calculateReservations(_totalSupply);
    }
    function calculateReservations(uint256 _totalSupply) private {
    function calculateReservations(uint256 _totalSupply) private {
    reservedTokensTeam = _totalSupply.mul(reserveTokensTeamPercent).div(100);
    reservedTokensCrowdsalePurchase = 50 * (10**6); // 50m
    reservedTokensCrowdsalePurchase = 50 * (10 ** 6);
    // 50m
    }
    }

    library SafeERC20 {
    function safeTransfer(
    ERC20Basic _token,
    address _to,
    uint256 _value
    )
    internal
    internal
    {
    require(_token.transfer(_to, _value));
    }
    function safeTransferFrom(

    function safeTransferFrom(
    ERC20 _token,
    address _from,
    address _to,
    uint256 _value
    )
    internal
    internal
    {
    require(_token.transferFrom(_from, _to, _value));
    }
    function safeApprove(

    function safeApprove(
    ERC20 _token,
    address _spender,
    uint256 _value
    )
    internal
    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(

    event TokenPurchase(
    address indexed purchaser,
    address indexed beneficiary,
    uint256 value,
    uint256 amount
    );
    constructor(uint256 _rate, address _wallet, ERC20 _token) public {
    constructor(uint256 _rate, address _wallet, ERC20 _token) public {
    require(_rate > 0);
    require(_wallet != address(0));
    require(_token != address(0));
    rate = _rate;
    rate = _rate;
    wallet = _wallet;
    token = _token;
    }
    function () external payable {
    function() external payable {
    buyTokens(msg.sender);
    }
    function buyTokens(address _beneficiary) public payable {
    uint256 weiAmount = msg.value;

    function buyTokens(address _beneficiary) public payable {
    uint256 weiAmount = msg.value;
    _preValidatePurchase(_beneficiary, weiAmount);
    uint256 tokens = _getTokenAmount(weiAmount);
    weiRaised = weiRaised.add(weiAmount);
    _processPurchase(_beneficiary, tokens);
    _processPurchase(_beneficiary, tokens);
    emit TokenPurchase(
    msg.sender,
    _beneficiary,
    weiAmount,
    tokens
    );
    _updatePurchasingState(_beneficiary, weiAmount);
    _forwardFunds();
    _updatePurchasingState(_beneficiary, weiAmount);
    _forwardFunds();
    _postValidatePurchase(_beneficiary, weiAmount);
    }
    function _preValidatePurchase(

    function _preValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
    )
    internal
    internal
    {
    require(_beneficiary != address(0));
    require(_weiAmount != 0);
    }
    function _postValidatePurchase(

    function _postValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
    )
    internal
    internal
    {
    }
    function _deliverTokens(

    function _deliverTokens(
    address _beneficiary,
    uint256 _tokenAmount
    )
    internal
    internal
    {
    token.safeTransfer(_beneficiary, _tokenAmount);
    }
    function _processPurchase(

    function _processPurchase(
    address _beneficiary,
    uint256 _tokenAmount
    )
    internal
    internal
    {
    _deliverTokens(_beneficiary, _tokenAmount);
    }
    function _updatePurchasingState(

    function _updatePurchasingState(
    address _beneficiary,
    uint256 _weiAmount
    )
    internal
    internal
    {
    }
    function _getTokenAmount(uint256 _weiAmount)
    internal view returns (uint256)

    function _getTokenAmount(uint256 _weiAmount)
    internal view returns (uint256)
    {
    return _weiAmount.mul(rate);
    }
    function _forwardFunds() internal {

    function _forwardFunds() internal {
    wallet.transfer(msg.value);
    }
    }

    contract TimedCrowdsale is Crowdsale {
    using SafeMath for uint256;
    uint256 public openingTime;
    uint256 public openingTime;
    uint256 public closingTime;
    modifier onlyWhileOpen {
    modifier onlyWhileOpen {
    require(block.timestamp >= openingTime && block.timestamp <= closingTime);
    _;
    }
    constructor(uint256 _openingTime, uint256 _closingTime) public {
    constructor(uint256 _openingTime, uint256 _closingTime) public {
    require(_openingTime >= block.timestamp);
    require(_closingTime >= _openingTime);
    openingTime = _openingTime;
    openingTime = _openingTime;
    closingTime = _closingTime;
    }
    function hasClosed() public view returns (bool) {
    function hasClosed() public view returns (bool) {
    return block.timestamp > closingTime;
    }
    function _preValidatePurchase(

    function _preValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
    )
    internal
    onlyWhileOpen
    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 {
    bool public isFinalized = false;

    event Finalized();

    function finalize() public onlyOwner {
    require(!isFinalized);
    require(hasClosed());
    finalization();
    finalization();
    emit Finalized();
    isFinalized = true;
    isFinalized = true;
    }
    function finalization() internal {

    function finalization() internal {
    }
    }

    contract WAS_Crowdsale_Stages is FinalizableCrowdsale, WAS_CrowdsaleReservations {
    uint256[] rateETH;
    uint256[] openingTimings;
    uint256[] closingTimings;
    uint256[] stagePurchaseTokensMinimum;
    modifier onlyWhileOpen {
    modifier onlyWhileOpen {
    bool stageRunning;
    uint256 stageIdx;
    (stageRunning, stageIdx) = currentStage();
    require(stageRunning, "no stage is currently running");
    require(stageRunning, "no stage is currently running");
    _;
    }
    constructor(uint256[] _rateETH, uint256[] _openingTimings, uint256[] _closingTimings)
    constructor(uint256[] _rateETH, uint256[] _openingTimings, uint256[] _closingTimings)
    TimedCrowdsale(_openingTimings[0], _closingTimings[_closingTimings.length - 1])
    public {
    validateRates(_rateETH);
    validateOpeningAndClosingTimings(_openingTimings, _closingTimings);
    rateETH = _rateETH;
    rateETH = _rateETH;
    openingTimings = _openingTimings;
    closingTimings = _closingTimings;
    stagePurchaseTokensMinimum = [0, 100];
    }
    function hasOpened() public view returns (bool) {
    function hasOpened() public view returns (bool) {
    return now >= openingTime;
    }
    function currentRateETH() public view returns (uint256) {

    function currentRateETH() public view returns (uint256) {
    bool stageRunning;
    uint256 stageIdx;
    (stageRunning, stageIdx) = currentStage();
    require(stageRunning, "no stage is currently running");
    require(stageRunning, "no stage is currently running");
    return rateETH[stageIdx];
    }
    function currentDiscount(uint256 _tokenPurchasedAmount) public view returns (uint256) {

    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);
    require(stageRunning, "no stage is currently running");
    return discountPercentForStage(stageIdx, _tokenPurchasedAmount);
    }
    function currentStage() public view returns (bool, uint256) {

    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 (true, i);
    }
    }
    return(false, 0);
    return (false, 0);
    }
    function updateStageRateETH(uint256 _stage, uint256 _rateETH) public onlyOwner {

    function updateStageRateETH(uint256 _stage, uint256 _rateETH) public onlyOwner {
    rateETH[_stage] = _rateETH;
    }
    function updateOpeningAndClosingTimings(uint256[] _openingTimings, uint256[] _closingTimings) public onlyOwner {

    function updateOpeningAndClosingTimings(uint256[] _openingTimings, uint256[] _closingTimings) public onlyOwner {
    validateOpeningAndClosingTimings(_openingTimings, _closingTimings);
    openingTimings = _openingTimings;
    openingTimings = _openingTimings;
    closingTimings = _closingTimings;
    }
    function validateRates(uint256[] _rateETH) private pure {

    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 {

    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 ++) {
    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");
    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) {

    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;
    }
    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() {

    bool public paused = false;
    modifier whenNotPaused() {
    require(!paused);
    _;
    }
    modifier whenPaused() {
    modifier whenPaused() {
    require(paused);
    _;
    }
    function pause() public onlyOwner whenNotPaused {
    function pause() public onlyOwner whenNotPaused {
    paused = true;
    emit Pause();
    }
    function unpause() public onlyOwner whenPaused {

    function unpause() public onlyOwner whenPaused {
    paused = false;
    emit Unpause();
    }
    }

    library Roles {
    struct Role {
    mapping (address => bool) bearer;
    mapping(address => bool) bearer;
    }
    function add(Role storage _role, address _addr)
    internal

    function add(Role storage _role, address _addr)
    internal
    {
    _role.bearer[_addr] = true;
    }
    function remove(Role storage _role, address _addr)
    internal

    function remove(Role storage _role, address _addr)
    internal
    {
    _role.bearer[_addr] = false;
    }
    function check(Role storage _role, address _addr)
    internal
    view

    function check(Role storage _role, address _addr)
    internal
    view
    {
    require(has(_role, _addr));
    }
    function has(Role storage _role, address _addr)
    internal
    view
    returns (bool)

    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);
    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

    function checkRole(address _operator, string _role)
    public
    view
    {
    roles[_role].check(_operator);
    }
    function hasRole(address _operator, string _role)
    public
    view
    returns (bool)

    function hasRole(address _operator, string _role)
    public
    view
    returns (bool)
    {
    return roles[_role].has(_operator);
    }
    function addRole(address _operator, string _role)
    internal

    function addRole(address _operator, string _role)
    internal
    {
    roles[_role].add(_operator);
    emit RoleAdded(_operator, _role);
    }
    function removeRole(address _operator, string _role)
    internal

    function removeRole(address _operator, string _role)
    internal
    {
    roles[_role].remove(_operator);
    emit RoleRemoved(_operator, _role);
    }
    modifier onlyRole(string _role)
    modifier onlyRole(string _role)
    {
    checkRole(msg.sender, _role);
    _;
    }
    }

    contract Whitelist is Ownable, RBAC {
    string public constant ROLE_WHITELISTED = "whitelist";
    modifier onlyIfWhitelisted(address _operator) {
    modifier onlyIfWhitelisted(address _operator) {
    checkRole(_operator, ROLE_WHITELISTED);
    _;
    }
    function addAddressToWhitelist(address _operator)
    public
    onlyOwner
    function addAddressToWhitelist(address _operator)
    public
    onlyOwner
    {
    addRole(_operator, ROLE_WHITELISTED);
    }
    function whitelist(address _operator)
    public
    view
    returns (bool)

    function whitelist(address _operator)
    public
    view
    returns (bool)
    {
    return hasRole(_operator, ROLE_WHITELISTED);
    }
    function addAddressesToWhitelist(address[] _operators)
    public
    onlyOwner

    function addAddressesToWhitelist(address[] _operators)
    public
    onlyOwner
    {
    for (uint256 i = 0; i < _operators.length; i++) {
    addAddressToWhitelist(_operators[i]);
    }
    }
    function removeAddressFromWhitelist(address _operator)
    public
    onlyOwner

    function removeAddressFromWhitelist(address _operator)
    public
    onlyOwner
    {
    removeRole(_operator, ROLE_WHITELISTED);
    }
    function removeAddressesFromWhitelist(address[] _operators)
    public
    onlyOwner

    function removeAddressesFromWhitelist(address[] _operators)
    public
    onlyOwner
    {
    for (uint256 i = 0; i < _operators.length; i++) {
    removeAddressFromWhitelist(_operators[i]);
    }
    }
    }

    contract WhitelistedCrowdsale is Whitelist, Crowdsale {
    function _preValidatePurchase(
    function _preValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
    )
    internal
    onlyIfWhitelisted(_beneficiary)
    internal
    onlyIfWhitelisted(_beneficiary)
    {
    super._preValidatePurchase(_beneficiary, _weiAmount);
    }
    }

    contract Destructible is Ownable {
    function destroy() public onlyOwner {
    function destroy() public onlyOwner {
    selfdestruct(owner);
    }
    function destroyAndSend(address _recipient) public onlyOwner {

    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)
    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);
    token = WAS_Token(_token);
    }
    function mintTotalSupplyAndTeam(address _teamAddress) public onlyOwner {
    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(_teamAddress, reservedTokensTeam);
    uint256 purchaseTokens = token.totalSupplyLimit().sub(reservedTokensTeam);
    token.mint(address(this), purchaseTokens);
    token.finishMinting();
    token.finishMinting();
    }
    function manualTransfer(address _to, uint256 _tokenAmount) public onlyOwner {

    function manualTransfer(address _to, uint256 _tokenAmount) public onlyOwner {
    bool stageRunning;
    uint256 stageIdx;
    (stageRunning, stageIdx) = currentStage();
    require(stageRunning, "no stage is currently running");
    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);
    token.transfer(_to, _tokenAmount);
    }
    function destroy() public onlyOwner {

    function destroy() public onlyOwner {
    require(hasClosed(), "crowdsale must be closed");
    require(isFinalized, "crowdsale must be finalized");
    selfdestruct(owner);
    selfdestruct(owner);
    }
    function destroyAndSend(address _recipient) public onlyOwner {

    function destroyAndSend(address _recipient) public onlyOwner {
    require(hasClosed(), "crowdsale must be closed");
    require(isFinalized, "crowdsale must be finalized");
    selfdestruct(_recipient);
    selfdestruct(_recipient);
    }
    function finalization() internal {

    function finalization() internal {
    uint256 unpurchasedTokens = token.balanceOf(address(this));
    token.transfer(owner, unpurchasedTokens);
    super.finalization();
    super.finalization();
    }
    function _preValidatePurchase(

    function _preValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
    )
    internal
    whenNotPaused()
    onlyWhileOpen()
    internal
    whenNotPaused()
    onlyWhileOpen()
    {
    super._preValidatePurchase(_beneficiary, _weiAmount);
    }
    function _getTokenAmount(uint256 _weiAmount)
    internal view returns (uint256)

    function _getTokenAmount(uint256 _weiAmount)
    internal view returns (uint256)
    {
    uint256 rateETH = currentRateETH();
    uint256 tokens = _weiAmount.mul(rateETH).div(uint256(10**18));
    uint256 tokens = _weiAmount.mul(rateETH).div(uint256(10 ** 18));
    uint256 discount = currentDiscount(tokens);
    if (discount > 0) {
    tokens = tokens.add(tokens.mul(discount).div(100));
    tokens = tokens.add(tokens.mul(discount).div(100));
    }
    return tokens;
    }
    function _processPurchase(

    function _processPurchase(
    address _beneficiary,
    uint256 _tokenAmount
    )
    internal
    internal
    {
    bool stageRunning;
    uint256 stageIdx;
    (stageRunning, stageIdx) = currentStage();
    require(stageRunning, "no stage is currently running");
    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");
    require(tokensCrowdsalePurchased.add(_tokenAmount) <= reservedTokensCrowdsalePurchase, "not enough tokens to purchase");
    tokensCrowdsalePurchased = tokensCrowdsalePurchased.add(_tokenAmount);
    super._processPurchase(_beneficiary, _tokenAmount);
    super._processPurchase(_beneficiary, _tokenAmount);
    }
    }
  2. @labiak labiak created this gist Oct 18, 2018.
    685 changes: 685 additions & 0 deletions flattened.sol
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,685 @@
    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);
    }
    }