contract MainSale is Ownable, Authorizable {
    using SafeMath for uint;
    event TokenSold(address recipient, uint ether_amount, uint pay_amount, uint exchangerate);
    event AuthorizedCreate(address recipient, uint pay_amount);
    event AuthorizedBurn(address receiver, uint value);
    event AuthorizedStartTrading();
    event MainSaleClosed();
    CBCToken public token = new CBCToken();

    address payable public multisigVault;

    uint hardcap = 100000000000000 ether;
    ExchangeRate public exchangeRate;

    uint public altDeposits = 0;
    uint public start = 1525996800;

    /**
     * @dev modifier to allow token creation only when the sale IS ON
     */
    modifier saleIsOn() {
        require(now > start && now < start + 28 days);
        _;
    }

    /**
     * @dev modifier to allow token creation only when the hardcap has not been reached
     */
    modifier isUnderHardCap() {
        require(multisigVault.balance + altDeposits <= hardcap);
        _;
    }

    /**
     * @dev Allows anyone to create tokens by depositing ether.
     * @param recipient the recipient to receive tokens.
     */
    function createTokens(address recipient) public isUnderHardCap saleIsOn payable {
        uint rate = exchangeRate.getRate("ETH");
        uint tokens = rate.mul(msg.value).div(1 ether);
        token.mint(recipient, tokens);
        require(multisigVault.send(msg.value));
        emit TokenSold(recipient, msg.value, tokens, rate);
    }

    /**
     * @dev Allows to set the toal alt deposit measured in ETH to make sure the hardcap includes other deposits
     * @param totalAltDeposits total amount ETH equivalent
     */
    function setAltDeposit(uint totalAltDeposits) public onlyOwner {
        altDeposits = totalAltDeposits;
    }

    /**
     * @dev Allows authorized acces to create tokens. This is used for Bitcoin and ERC20 deposits
     * @param recipient the recipient to receive tokens.
     * @param tokens number of tokens to be created.
     */
    function authorizedCreateTokens(address recipient, uint tokens) public onlyAuthorized {
        token.mint(recipient, tokens);
        emit AuthorizedCreate(recipient, tokens);
    }

    function authorizedStartTrading() public onlyAuthorized {
        token.startTrading();
        emit AuthorizedStartTrading();
    }

    /**
     * @dev Allows authorized acces to burn tokens.
     * @param receiver the receiver to receive tokens.
     * @param value number of tokens to be created.
     */
    function authorizedBurnTokens(address receiver, uint value) public onlyAuthorized {
        token.burn(receiver, value);
        emit AuthorizedBurn(receiver, value);
    }

    /**
     * @dev Allows the owner to set the hardcap.
     * @param _hardcap the new hardcap
     */
    function setHardCap(uint _hardcap) public onlyOwner {
        hardcap = _hardcap;
    }

    /**
     * @dev Allows the owner to set the starting time.
     * @param _start the new _start
     */
    function setStart(uint _start) public onlyOwner {
        start = _start;
    }

    /**
     * @dev Allows the owner to set the multisig contract.
     * @param _multisigVault the multisig contract address
     */
    function setMultisigVault(address payable _multisigVault) public onlyOwner {
        if (_multisigVault != address(0)) {
            multisigVault = _multisigVault;
        }
    }

    /**
     * @dev Allows the owner to set the exchangerate contract.
     * @param _exchangeRate the exchangerate address
     */
    function setExchangeRate(address _exchangeRate) public onlyOwner {
        exchangeRate = ExchangeRate(_exchangeRate);
    }

    /**
     * @dev Allows the owner to finish the minting. This will create the
     * restricted tokens and then close the minting.
     * Then the ownership of the PAY token contract is transfered
     * to this owner.
     */
    function finishMinting() public onlyOwner {
        uint issuedTokenSupply = token.totalSupply();
        uint restrictedTokens = issuedTokenSupply.mul(49).div(51);
        token.mint(multisigVault, restrictedTokens);
        token.finishMinting();
        token.transferOwnership(owner);
        emit MainSaleClosed();
    }

    /**
     * @dev Allows the owner to transfer ERC20 tokens to the multi sig vault
     * @param _token the contract address of the ERC20 contract
     */
    function retrieveTokens(address _token) public onlyOwner {
        ERC20 token = ERC20(_token);
        token.transfer(multisigVault, token.balanceOf(address(this)));
    }

    /**
     * @dev Fallback function which receives ether and created the appropriate number of tokens for the
     * msg.sender.
     */
    function() external payable {
        createTokens(msg.sender);
    }

}
/**
 * @title MainSale
 * @dev The main CBC token sale contract
 *
 * ABI
 * [{"constant":false,"inputs":[{"name":"_multisigVault","type":"address"}],"name":"setMultisigVault","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"authorizerIndex","type":"uint256"}],"name":"getAuthorizer","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"exchangeRate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"altDeposits","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"recipient","type":"address"},{"name":"tokens","type":"uint256"}],"name":"authorizedCreateTokens","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"finishMinting","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_exchangeRate","type":"address"}],"name":"setExchangeRate","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"retrieveTokens","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"totalAltDeposits","type":"uint256"}],"name":"setAltDeposit","outputs":[],"payable":false,"type":"function"},{"constant":!1,"inputs":[{"name":"victim","type":"address"},{"name":"amount","type":"uint256"}],"name":"burnTokens","outputs":[],"payable":!1,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"start","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"recipient","type":"address"}],"name":"createTokens","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"}],"name":"addAuthorized","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"multisigVault","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_hardcap","type":"uint256"}],"name":"setHardCap","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_start","type":"uint256"}],"name":"setStart","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"isAuthorized","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"recipient","type":"address"},{"indexed":false,"name":"ether_amount","type":"uint256"},{"indexed":false,"name":"pay_amount","type":"uint256"},{"indexed":false,"name":"exchangerate","type":"uint256"}],"name":"TokenSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"recipient","type":"address"},{"indexed":false,"name":"pay_amount","type":"uint256"}],"name":"AuthorizedCreate","type":"event"},{"anonymous":false,"inputs":[],"name":"MainSaleClosed","type":"event"}]
 */
function createTokens(address recipient) public isUnderHardCap saleIsOn payable {
    uint rate = exchangeRate.getRate("ETH");
    uint tokens = rate.mul(msg.value).div(1 ether);
    token.mint(recipient, tokens);
    require(multisigVault.send(msg.value));
    emit TokenSold(recipient, msg.value, tokens, rate);
}

/**
 * @dev Allows anyone to create tokens by depositing ether.
 * @param recipient the recipient to receive tokens.
 */