contract ToshiCoinNonTradable is Ownable, MinterRole, CanTransferRole {
    using SafeMath for uint256;

    event Transfer(address indexed from, address indexed to, uint256 value);

    mapping(address => uint256) private _balances;

    string public name = "ToshiCoin - Non Tradable";
    string public symbol = "ToshiCoin";
    uint8 public decimals = 18;

    uint256 public totalSupply;
    uint256 public totalClaimed;
    uint256 public totalMinted;

    uint256 public remainingToshiCoinForSale = 4000 * (1e18);
    uint256 public priceInTOSHI = 3;

    IERC20 public toshi;
    address public toshiTreasury;

    constructor(IERC20 _toshi, address _toshiTreasury) public {
        toshi = _toshi;
        toshiTreasury = _toshiTreasury;
    }

    function addClaimed(uint256 amount) internal {
        totalClaimed = totalClaimed.add(amount);
    }

    function addMinted(uint256 amount) internal {
        totalMinted = totalMinted.add(amount);
    }

    function setRemainingToshiCoinForSale(uint256 _remainingToshiCoinForSale)
        external
        onlyMinter
    {
        remainingToshiCoinForSale = _remainingToshiCoinForSale;
    }

    function setPriceInToshi(uint256 _priceInTOSHI) external onlyMinter {
        priceInTOSHI = _priceInTOSHI;
    }

    function setToshiTreasury(address _toshiTreasury) external onlyMinter {
        toshiTreasury = _toshiTreasury;
    }

    /**
     * @dev Anyone can purchase ToshiCoin for TOSHI until it is sold out.
     */
    function purchase(uint256 amount) external {
        uint256 price = priceInTOSHI.mul(amount);
        uint256 balance = toshi.balanceOf(msg.sender);

        require(balance >= price, "ToshiCoin: Not enough TOSHI in wallet.");
        require(
            remainingToshiCoinForSale >= amount,
            "ToshiCoin: Not enough ToshiCoin for sale."
        );

        safeToshiTransferFrom(msg.sender, toshiTreasury, price);

        remainingToshiCoinForSale = remainingToshiCoinForSale.sub(amount);

        _mint(msg.sender, amount);
        addMinted(amount);
    }

    /**
     * @dev Claiming is white-listed to specific minter addresses for now to limit transfers.
     */
    function claim(address to, uint256 amount) public onlyCanTransfer {
        transfer(to, amount);
        addClaimed(amount);
    }

    /**
     * @dev Transferring is white-listed to specific minter addresses for now.
     */
    function transfer(address to, uint256 amount)
        public
        onlyCanTransfer
        returns (bool)
    {
        require(
            amount <= _balances[msg.sender],
            "ToshiCoin: Cannot transfer more than balance"
        );

        _balances[msg.sender] = _balances[msg.sender].sub(amount);
        _balances[to] = _balances[to].add(amount);

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    /**
     * @dev Transferring is white-listed to specific minter addresses for now.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public onlyCanTransfer returns (bool) {
        require(
            amount <= _balances[from],
            "ToshiCoin: Cannot transfer more than balance"
        );

        _balances[from] = _balances[from].sub(amount);
        _balances[to] = _balances[to].add(amount);

        emit Transfer(from, to, amount);

        return true;
    }

    /**
     * @dev Gets the balance of the specified address.
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev Minting is white-listed to specific minter addresses for now.
     */
    function mint(address to, uint256 amount) public onlyMinter {
        _mint(to, amount);
        addMinted(amount);
    }

    /**
     * @dev Burning is white-listed to specific minter addresses for now.
     */
    function burn(address from, uint256 value) public onlyCanTransfer {
        require(
            _balances[from] >= value,
            "ToshiCoin: Cannot burn more than the address balance"
        );

        _burn(from, value);
    }

    /**
     * @dev Internal function that creates an amount of the token and assigns it to an account.
     * This encapsulates the modification of balances such that the proper events are emitted.
     * @param to The account that will receive the created tokens.
     * @param amount The amount that will be created.
     */
    function _mint(address to, uint256 amount) internal {
        require(to != address(0), "ToshiCoin: mint to the zero address");

        totalSupply = totalSupply.add(amount);
        _balances[to] = _balances[to].add(amount);

        emit Transfer(address(0), to, amount);
    }

    /**
     * @dev Internal function that destroys an amount of the token of a given address.
     * @param from The account whose tokens will be destroyed.
     * @param amount The amount that will be destroyed.
     */
    function _burn(address from, uint256 amount) internal {
        require(from != address(0), "ToshiCoin: burn from the zero address");

        totalSupply = totalSupply.sub(amount);
        _balances[from] = _balances[from].sub(amount);

        emit Transfer(from, address(0), amount);
    }

    /**
     * @dev Safe token transfer from to prevent over-transfers.
     */
    function safeToshiTransferFrom(
        address from,
        address to,
        uint256 amount
    ) internal {
        uint256 tokenBalance = toshi.balanceOf(address(from));
        uint256 transferAmount = amount > tokenBalance ? tokenBalance : amount;

        toshi.transferFrom(from, to, transferAmount);
    }
}
function purchase(uint256 amount) external {
    uint256 price = priceInTOSHI.mul(amount);
    uint256 balance = toshi.balanceOf(msg.sender);

    require(balance >= price, "ToshiCoin: Not enough TOSHI in wallet.");
    require(
        remainingToshiCoinForSale >= amount,
        "ToshiCoin: Not enough ToshiCoin for sale."
    );

    safeToshiTransferFrom(msg.sender, toshiTreasury, price);

    remainingToshiCoinForSale = remainingToshiCoinForSale.sub(amount);

    _mint(msg.sender, amount);
    addMinted(amount);
}

/**
 * @dev Anyone can purchase ToshiCoin for TOSHI until it is sold out.
 */