function buyTokens(
        address _tokenReceiver,
        address _referrer,
        uint256 _couponCampaignId, 
        uint256 _tokenPrice,
        uint256 _minWei,
        uint256 _expiration,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) payable external nonReentrant {
        require(_expiration >= now, "Signature expired");
        require(_tokenReceiver != 0x0, "Token receiver must be provided");
        require(_minWei > 0, "Minimal amount to purchase must be greater than 0");

        require(wallet != 0x0, "Wallet must be set");
        require(msg.value >= _minWei, "Purchased amount is less than min amount to invest");

        address receivedSigner = ecrecover(
            keccak256(
                abi.encodePacked(
                    _tokenPrice, _minWei, _tokenReceiver, _referrer, _couponCampaignId, _expiration
                )
            ), _v, _r, _s);

        require(receivedSigner == signer, "Something wrong with signature");

        uint256 tokensAmount = msg.value.mul(10 ** uint256(signkeysToken.decimals())).div(_tokenPrice);
        require(signkeysToken.balanceOf(this) >= tokensAmount, "Not enough tokens in sale contract");

        
        signkeysToken.transfer(_tokenReceiver, tokensAmount);

        
        signkeysBonusProgram.sendBonus(
            _referrer,
            _tokenReceiver,
            tokensAmount,
            (tokensAmount.mul(tokenPriceCents).div(10 ** uint256(signkeysToken.decimals()))),
            _couponCampaignId);

        
        wallet.transfer(msg.value);

        emit BuyTokens(msg.sender, _tokenReceiver, _tokenPrice, tokensAmount);
    }