function buyToken()
        external
        inState(States.Active)
        payable
    {
        
        
        if (kycLevel > 0) {
            require(
                
                block.timestamp < kyc.expireOf(msg.sender),
                "Failed to buy token due to KYC was expired."
            );
        }

        require(
            kycLevel <= kyc.kycLevelOf(msg.sender),
            "Failed to buy token due to require higher KYC level."
        );

        require(
            countryBlacklist & kyc.nationalitiesOf(msg.sender) == 0 || (
                kyc.kycLevelOf(msg.sender) >= 200 && legalPersonSkipsCountryCheck
            ),
            "Failed to buy token due to country investment restriction."
        );

        
        (uint256 _exRate, uint8 _exRateDecimals) = exRate.currencies(currency);

        
        uint256 _investSize = (msg.value)
            .mul(_exRate).div(10**uint256(_exRateDecimals));

        require(
            _investSize >= minInvest,
            "Failed to buy token due to less than minimum investment."
        );

        require(
            raised.add(_investSize) <= cap,
            "Failed to buy token due to exceed cap."
        );

        require(
            
            block.timestamp < closingTime,
            "Failed to buy token due to crowdsale is closed."
        );

        
        invests[msg.sender] = invests[msg.sender].add(_investSize);
        
        deposits[msg.sender] = deposits[msg.sender].add(msg.value);
        
        raised = raised.add(_investSize);

        
        uint256 _previousTokenUnits = tokenUnits[msg.sender];

        
        uint256 _tokenUnits = invests[msg.sender]
            .mul(baseExRate)
            .div(10**uint256(baseExRateDecimals));

        
        uint256 _tokenUnitsWithBonus = _tokenUnits.add(
            _getBonus(invests[msg.sender], _tokenUnits));

        
        tokenUnits[msg.sender] = _tokenUnitsWithBonus;

        
        totalTokenUnits = totalTokenUnits
            .sub(_previousTokenUnits)
            .add(_tokenUnitsWithBonus);

        emit TokenBought(msg.sender, msg.value, _investSize);

        
        vault.deposit.value(msg.value)();
    }