// File: CTPurchaseOffer.sol



pragma solidity ^0.5.17;

import "./GTTokenInterface.sol";
import "./SafeMath.sol";


/**
 * @title CTPurchaseOffer
 * @dev The CTPurchaseOffer contract helps in creating a purchase offer contract
 */
contract CTPurchaseOffer {

    // Struct Offer to define parameters for the purchase offer
    struct Offer {
        address buyer;
        address seller;
        uint gtAmount;
        string companyTokenName;
        uint companyTokenAmount;
        bool active;
        bool completed;
    }

    // Event to be emitted when purchase offer is withdrawn
    event WithdrawPurchaseOffer(address indexed buyerAddress);

    using SafeMath for uint256;

    GTTokenInterface public tokenController;
    Offer public offer;

    /**
     * @dev Constructor, sets the defining parameters for the company token purchase contract by the buyer
     */
    constructor(
        address gtTokenAddress,
        address seller,
        uint gtAmount,
        string memory companyTokenName,
        uint companyTokenAmount
    )
        public
    {
        require(gtTokenAddress != address(0x0));
        tokenController = GTTokenInterface(gtTokenAddress);

        require(tokenController.isInvestorRegistered(msg.sender));
        require(tokenController.isInvestorRegistered(seller));
        require(companyTokenAmount > 0);

        require(tokenController.balanceOf(msg.sender) >= gtAmount);

        offer = Offer(
            msg.sender,
            seller,
            gtAmount,
            companyTokenName,
            companyTokenAmount,
            false,
            false
        );
    }

    modifier onlyTokenContract() {
        require(msg.sender == address(tokenController));
        _;
    }

    function getSeller() external view returns(address) {
        return offer.seller;
    }

    function getBuyer() external view returns(address) {
        return offer.buyer;
    }

    function isOfferCompleted() external view returns(bool) {
        return offer.completed;
    }

    function isOfferActive() external view returns(bool) {
        return offer.active;
    }

    function getCompanyTokenName() external view returns(string memory) {
        return offer.companyTokenName;
    }

    function getCompanyTokenAmount() external view returns(uint) {
        return offer.companyTokenAmount;
    }

    function getGTAmount() external view returns(uint) {
        return offer.gtAmount;
    }

    /**
     * @dev Allows activation of purchase offer contract by the buyer.
     * Can only be called from GT Token contract
     */
    function activateOffer() external onlyTokenContract {
        offer.active = true;
    }

    /**
     * @dev Allows withdrawal of purchase offer contract by the buyer.
     * Can only be called by the buyer or the seller
     */
    function withdrawOffer() external {
        require(offer.buyer == msg.sender || offer.seller == msg.sender);
        require(offer.active);

        tokenController.transfer(offer.buyer, offer.gtAmount);
        offer.active = false;

        emit WithdrawPurchaseOffer(address(this));
    }

    /**
     * @dev Allows acceptance of purchase offer contract by the seller.
     * Can only be caller from GT Token contract
     */
    function acceptOffer() external onlyTokenContract {
        uint fee = (offer.gtAmount).div(100);

        tokenController.transfer(offer.seller, (offer.gtAmount).sub(fee));
        tokenController.burnTokens(fee);

        offer.active = false;
        offer.completed = true;
    }
}

// File: CTSellOffer.sol



pragma solidity ^0.5.17;

import "./GTTokenInterface.sol";


/**
 * @title CTSellOffer
 * @dev The CTSellOffer contract helps in creating a sell offer contract
 */
contract CTSellOffer {

    // Struct Offer to define parameters for the sell offer
    struct Offer {
        address buyer;
        address seller;
        uint gtAmount;
        string companyTokenName;
        uint companyTokenAmount;
        bool active;
        bool completed;
    }

    GTTokenInterface public tokenController;
    Offer public offer;

    /**
     * @dev Constructor, sets the defining parameters for the company token sell contract by the seller
     */
    constructor(
        address gtTokenAddress,
        address buyer,
        uint gtAmount,
        string memory companyTokenName,
        uint companyTokenAmount
    )
        public
    {
        require(gtTokenAddress != address(0x0));
        tokenController = GTTokenInterface(gtTokenAddress);

        require(tokenController.isInvestorRegistered(msg.sender));
        require(tokenController.isInvestorRegistered(buyer));
        require(gtAmount > 0);

        require(tokenController.getCompanyTokenBalance(companyTokenName, msg.sender) >= companyTokenAmount);

        offer = Offer(
            buyer,
            msg.sender,
            gtAmount,
            companyTokenName,
            companyTokenAmount,
            false,
            false
        );
    }

    modifier onlyTokenContract() {
        require(msg.sender == address(tokenController));
        _;
    }

    function getSeller() external view returns(address) {
        return offer.seller;
    }

    function getBuyer() external view returns(address) {
        return offer.buyer;
    }

    function isOfferCompleted() external view returns(bool) {
        return offer.completed;
    }

    function isOfferActive() external view returns(bool) {
        return offer.active;
    }

    function getCompanyTokenName() external view returns(string memory) {
        return offer.companyTokenName;
    }

    function getCompanyTokenAmount() external view returns(uint) {
        return offer.companyTokenAmount;
    }

    function getGTAmount() external view returns(uint) {
        return offer.gtAmount;
    }

    /**
     * @dev Allows activation of sell offer contract by the seller.
     * Can only be called from GT Token contract
     */
    function activateOffer() external onlyTokenContract {
        offer.active = true;
    }

    /**
     * @dev Allows de-activation of sell offer contract by the seller.
     * Can only be called from GT Token contract
     */
    function deActivateOffer() external onlyTokenContract {
        offer.active = false;
    }

    /**
     * @dev Allows acceptance of sell offer contract by the buyer.
     * Can only be called from GT Token contract
     */
    function acceptOffer() external onlyTokenContract {
        offer.completed = true;
        offer.active = false;
    }
}

// File: ERC20.sol



pragma solidity ^0.5.17;

import "./IERC20.sol";
import "./SafeMath.sol";


/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20Mintable}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public returns (bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20};
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for `sender`'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of `from`'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of `from`'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:using-hooks.adoc[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal { }
}

// File: GTToken.sol



pragma solidity ^0.5.17;

import "./CTPurchaseOffer.sol";
import "./CTSellOffer.sol";
import "./SafeMath.sol";
import "./Ownable.sol";
import "./Implementation.sol";
import "./ERC20.sol";


/**
 * @title GTToken
 * @dev The GTToken contract is an ERC20 standard based token implementation
 * It extends the Burnable, Detailed, Mintable, Pausable and Ownable functionalities
 */
contract GTToken is Implementation, Ownable, ERC20 {


    /* Usings */

    using SafeMath for uint256;


    /* Events */

    event GTTokenSetup(bool isSetup);
    event InvestorRegistered(address indexed investorRegistered);
    event CompanyTokenRegistered(
        string companyTokenName,
        uint indexed companyTokenAmounts
    );
    event CompanyTokenDistributed(
        string companyTokenName,
        address indexed initialShareHolders,
        uint indexed companyTokenAmounts,
        uint indexed distributedAmount
    );
    event CompanyTokenTransferred(
        string companyTokenName,
        address indexed fromAddress,
        address indexed toAddress,
        uint indexed amount
    );
    event AllocateTokens(
        address indexed investorAddress,
        uint indexed tokenAmount
    );
    event BurnTokens(
        address indexed investorAddress,
        uint indexed gtBalance
    );
    event ActivatePurchaseOffer(address indexed purchaseContract);
    event ActivateSellOffer(address indexed sellContract);
    event AcceptPurchaseOffer(address indexed purchaseContract);
    event AcceptSellOffer(address indexed sellContract);
    event WithdrawSellOffer(address indexed sellContract);


    /* Modifiers */

    modifier isGTTokenSetup() {
        require(isSetup);
        _;
    }

    modifier isAddressValid(address addr) {
        require(addr != address(0x0));
        _;
    }


    /* Storage */

    mapping (address => bool) investorRegistered;
    mapping (string => bool) companyTokenRegistered;
    mapping (string => uint) companyTokenCurrentSupply;
    mapping (string => uint) companyTokenCap;
    mapping (string => mapping (address => uint)) companyToken;

    string private name_;
    string private symbol_;
    uint8 private decimals_;


    /* External functions */

    /**
     * @dev Allows setting up of GTToken, sets the isSetup to true
     * @param _name string The name of the token
     * @param _symbol string The symbol of the token
     * @param _decimals uint The decimals for the token
     */
    function setup(
        string calldata _name,
        string calldata _symbol,
        uint8 _decimals
    )
        external
        returns(bool)
    {
        require(bytes(name_).length == 0 && bytes(_name).length > 0);
        require(bytes(symbol_).length == 0 && bytes(_symbol).length > 0);
        require(decimals_ == 0 && _decimals > 0);

        name_ = _name;
        symbol_ = _symbol;
        decimals_ = _decimals;

        isSetup = true;
        emit GTTokenSetup(isSetup);

        return true;
    }

    /**
     * @dev Allows registration of investor
     */
    function registerInvestor() external isGTTokenSetup returns(bool) {
        require(!investorRegistered[msg.sender]);

        investorRegistered[msg.sender] = true;

        emit InvestorRegistered(msg.sender);

        return true;
    }

    /**
     * @dev Returns true if the investor is registered
     * @param investorAddress address The address of the investor
     */
    function isInvestorRegistered(
        address investorAddress
    )
        external
        view
        returns(bool)
    {
        return investorRegistered[investorAddress];
    }

    /**
     * @return the name of the token.
     */
    function name() external view returns (string memory) {
        return name_;
    }

    /**
     * @return the symbol of the token.
     */
    function symbol() external view returns (string memory) {
        return symbol_;
    }

    function decimals() external view returns (uint8) {
        return decimals_;
    }

    /**
     * @dev Allows allocation of GT Token to investors
     * @param investorAddress address The address of the investor
     * @param tokenAmount uint The GT token amount to be allocated
     */
    function allocateTokens(
        address investorAddress,
        uint tokenAmount
    )
        external
        isGTTokenSetup
        onlyOwner

        returns(bool)
    {
        require(investorRegistered[investorAddress]);

        _mint(investorAddress, tokenAmount);

        emit AllocateTokens(investorAddress, balanceOf(investorAddress));

        return true;
    }

    /**
     * @dev Allows registration of a new company token. Can be called by the GT Admin/Owner only
     * @param companyTokenName string The name of company token
     */
    function registerCompanyToken(
        string calldata companyTokenName,
        uint ctTokenCap
    )
        external
        isGTTokenSetup
        onlyOwner
        returns(bool)
    {
        require(!companyTokenRegistered[companyTokenName]);
        require(ctTokenCap > 0);

        companyTokenRegistered[companyTokenName] = true;
        companyTokenCap[companyTokenName] = ctTokenCap;

        companyToken[companyTokenName][msg.sender] = ctTokenCap;

        emit CompanyTokenRegistered(companyTokenName, ctTokenCap);

        return true;
    }

    /**
     * @dev Provides functionality to distribute company token. Can be called by the GT Admin/Owner only
     * @param companyTokenName string The name of company token
     * @param initialShareHolders address[] The addresses of the investors for company token distribution
     * @param companyTokenAmounts uint[] The amount of the company token amount to be distributed
     */
    function distributeCompanyToken(
        string calldata companyTokenName,
        address[] calldata initialShareHolders,
        uint[] calldata companyTokenAmounts
    )
        external
        isGTTokenSetup
        onlyOwner
        returns(bool)
    {
        require(companyTokenRegistered[companyTokenName]);
        require(initialShareHolders.length == companyTokenAmounts.length);

        for (uint i = 0; i < initialShareHolders.length; i++) {
            require(investorRegistered[initialShareHolders[i]]);
        }

        uint askedSupply = companyTokenCurrentSupply[companyTokenName];

        for (uint i = 0; i < initialShareHolders.length; i++) {
            askedSupply = askedSupply.add(companyTokenAmounts[i]);
        }

        require(askedSupply <= companyTokenCap[companyTokenName]);

        for (uint i = 0; i < initialShareHolders.length; i++) {
            companyToken[companyTokenName][initialShareHolders[i]] = companyToken[companyTokenName][initialShareHolders[i]]
                .add(companyTokenAmounts[i]);
            companyToken[companyTokenName][msg.sender] = companyToken[companyTokenName][msg.sender].sub(companyTokenAmounts[i]);

            emit CompanyTokenDistributed(
                companyTokenName,
                initialShareHolders[i],
                companyToken[companyTokenName][initialShareHolders[i]],
                companyTokenAmounts[i]
            );
        }

        companyTokenCurrentSupply[companyTokenName] = askedSupply;

        return true;
    }

    /**
     * @dev Allows activation of purchase offer contracts
     * @param ctPurchaseOfferContract address The address of the purchase offer contract to be activated.
     * Can only be called by the purchase offer contract creator
     */
    function activatePurchaseOffer(
        address ctPurchaseOfferContract
    )
        external
        isAddressValid(ctPurchaseOfferContract)
        returns(bool)
    {
        CTPurchaseOffer ctPurchaseController = CTPurchaseOffer(ctPurchaseOfferContract);

        require(!ctPurchaseController.isOfferActive());
        require(!ctPurchaseController.isOfferCompleted());

        address buyer = ctPurchaseController.getBuyer();
        require(msg.sender == buyer);

        uint gtAmount = ctPurchaseController.getGTAmount();
        require(balanceOf(buyer) >= gtAmount);

        transfer(ctPurchaseOfferContract, gtAmount);
        ctPurchaseController.activateOffer();

        emit ActivatePurchaseOffer(ctPurchaseOfferContract);

        return true;
    }

    /**
     * @dev Allows activation of sell offer contracts
     * @param ctSellOfferContract address The address of the sell offer contract to be activated.
     * Can only be called by the sell offer contract creator
     */
    function activateSellOffer(
        address ctSellOfferContract
    )
        external
        isAddressValid(ctSellOfferContract)
        returns(bool)
    {
        CTSellOffer ctSellController = CTSellOffer(ctSellOfferContract);

        require(!ctSellController.isOfferActive());
        require(!ctSellController.isOfferCompleted());

        address seller = ctSellController.getSeller();
        require(msg.sender == seller);

        uint companyTokenAmount = ctSellController.getCompanyTokenAmount();
        string memory companyTokenName = ctSellController.getCompanyTokenName();

        require(getCompanyTokenBalance(companyTokenName, seller) >= companyTokenAmount);

        companyToken[companyTokenName][seller] = companyToken[companyTokenName][seller].sub(companyTokenAmount);
        companyToken[companyTokenName][ctSellOfferContract] = companyTokenAmount;
        ctSellController.activateOffer();

        emit ActivateSellOffer(ctSellOfferContract);

        return true;
    }

    /**
     * @dev Allows processing of acceptance of purchase offer contracts by a seller
     * @param ctPurchaseOfferContract address The address of the purchase offer contract to be accepted.
     * Can only be called by the registered seller of the purchase offer contract creator
     */
    function acceptPurchaseOffer(
        address ctPurchaseOfferContract
    )
        external
        isAddressValid(ctPurchaseOfferContract)
        returns(bool)
    {
        CTPurchaseOffer ctPurchaseController = CTPurchaseOffer(ctPurchaseOfferContract);
        require(ctPurchaseController.isOfferActive());

        address seller = ctPurchaseController.getSeller();
        require(seller == msg.sender);

        uint gtAmount = ctPurchaseController.getGTAmount();
        require(balanceOf(ctPurchaseOfferContract) == gtAmount);

        string memory companyTokenName = ctPurchaseController.getCompanyTokenName();
        uint tokenAmount = ctPurchaseController.getCompanyTokenAmount();

        require(getCompanyTokenBalance(companyTokenName, seller) >= tokenAmount);

        address buyer = ctPurchaseController.getBuyer();

        companyToken[companyTokenName][seller] = companyToken[companyTokenName][seller].sub(tokenAmount);
        companyToken[companyTokenName][buyer] = companyToken[companyTokenName][buyer].add(tokenAmount);

        ctPurchaseController.acceptOffer();

        emit AcceptPurchaseOffer(ctPurchaseOfferContract);
        emit CompanyTokenTransferred(
            companyTokenName,
            seller,
            buyer,
            tokenAmount
        );

        return true;
    }

    /**
     * @dev Allows processing of acceptance of sell offer contracts by a buyer
     * @param ctSellOfferContract address The address of the sell offer contract to be accepted.
     * Can only be called by the registered buyer of the sell offer contract creator
     */
    function acceptSellOffer(
        address ctSellOfferContract
    )
        external
        isAddressValid(ctSellOfferContract)
        returns(bool)
    {
        CTSellOffer ctSellController = CTSellOffer(ctSellOfferContract);
        require(ctSellController.isOfferActive());

        address buyer = ctSellController.getBuyer();
        require(msg.sender == buyer);


        uint companyTokenAmount = ctSellController.getCompanyTokenAmount();
        uint gtAmount = ctSellController.getGTAmount();
        string memory companyTokenName = ctSellController.getCompanyTokenName();

        require(balanceOf(buyer) >= gtAmount);
        require(getCompanyTokenBalance(companyTokenName, ctSellOfferContract) == companyTokenAmount);

        uint fee = gtAmount.div(100);

        delete companyToken[companyTokenName][ctSellOfferContract];
        companyToken[companyTokenName][buyer] = companyToken[companyTokenName][buyer].add(companyTokenAmount);

        address seller = ctSellController.getSeller();
        transfer(seller, gtAmount.sub(fee));
        burnTokens(fee);

        ctSellController.acceptOffer();

        emit AcceptSellOffer(ctSellOfferContract);
        emit CompanyTokenTransferred(
            companyTokenName,
            seller,
            buyer,
            companyTokenAmount
        );

        return true;
    }

    /**
     * @dev Allows withdrawal of the sell offer contracts by a seller
     * @param ctSellOfferContract address The address of the sell offer contract to be withdrawn.
     * Can only be called by the seller or buyer registered in the sell contract offer
     */
    function withdrawSellOffer(
        address ctSellOfferContract
    )
        external
        isAddressValid(ctSellOfferContract)
        returns(bool)
    {
        CTSellOffer ctSellController = CTSellOffer(ctSellOfferContract);
        require(ctSellController.isOfferActive());

        address seller = ctSellController.getSeller();
        address buyer = ctSellController.getBuyer();
        require(msg.sender == seller || msg.sender == buyer);

        uint companyTokenAmount = ctSellController.getCompanyTokenAmount();
        string memory companyTokenName = ctSellController.getCompanyTokenName();

        require(getCompanyTokenBalance(companyTokenName, ctSellOfferContract) == companyTokenAmount);

        companyToken[companyTokenName][seller] = companyToken[companyTokenName][seller].add(companyTokenAmount);
        delete companyToken[companyTokenName][ctSellOfferContract];

        ctSellController.deActivateOffer();

        emit WithdrawSellOffer(ctSellOfferContract);

        return true;
    }

    /* Public Functions */

    /**
     * @dev Returns the Company token balance of the investor
     * @param companyTokenName string The name of company token
     * @param investorAddress address The address of the investor
     */
    function getCompanyTokenBalance(
        string memory companyTokenName,
        address investorAddress
    )
        public
        view
        returns(uint)
    {
        return companyToken[companyTokenName][investorAddress];
    }

    /**
     * @dev Allows burning of investor GT Token
     * @param gtAmount uint The GT token amount to be allocated
     */
    function burnTokens(uint gtAmount) public returns(bool) {
        CTPurchaseOffer ctPurchaseController = CTPurchaseOffer(msg.sender);
        require(investorRegistered[msg.sender] || ctPurchaseController.isOfferActive());

        _burn(msg.sender, gtAmount);

        emit BurnTokens(msg.sender, balanceOf(msg.sender));

        return true;
    }
}

// File: GTTokenInterface.sol



pragma solidity ^0.5.17;

interface GTTokenInterface {
    function isInvestorRegistered(address addr) external view returns(bool);

    function balanceOf(address who) external view returns (uint256);

    function transfer(address to, uint256 value) external returns (bool);

    function owner() external view returns (address);

    function getCompanyTokenBalance(string calldata companyTokenName, address addr) external view returns(uint);

    function burnTokens(uint gtAmount) external returns(bool);
}

// File: GTTokenV2.sol



pragma solidity ^0.5.17;

import "./GTToken.sol";


/**
 * @title GTTokenV2
 * @dev The GTTokenV2 contract extends GTToken contract for upgradability testing
 */
contract GTTokenV2 is GTToken {


    /* Storage */

    uint256 public updatedTokenAmount;


    /* External functions */

    /**
     * @dev Allows setting up of GTTokenV2, sets the isSetup to true
     * @param _updatedTokenAmount uint The updated fixed token amount value
     */
    function setupV2(uint256 _updatedTokenAmount)
        external
        onlyOwner
    {
        require(updatedTokenAmount == 0 && _updatedTokenAmount > 0);

        updatedTokenAmount = _updatedTokenAmount;
        isSetup = true;
    }

    /**
     * @dev Allows allocation of GT Token to investors with V2 logic
     * @param investorAddress address The address of the investor
     * @param tokenAmount uint The GT token amount to be allocated
     */
    function allocateTokens(
        address investorAddress,
        uint tokenAmount
    )
        external

        isGTTokenSetup
        returns(bool)
    {
        require(investorRegistered[investorAddress]);
        require(tokenAmount == updatedTokenAmount);

        _mint(investorAddress, tokenAmount);

        emit AllocateTokens(investorAddress, balanceOf(investorAddress));

        return true;
    }
}

// File: IERC20.sol



pragma solidity ^0.5.17;


/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// File: Implementation.sol



pragma solidity ^0.5.17;


contract Implementation {

    bool public isSetup;
    address implementation;

    /**
     * @dev Sets the address of the current implementation
     * @param _newImp address of the new implementation
     */
    function _setImplementation(address _newImp) internal {
        implementation = _newImp;
    }
}

// File: Migrations.sol



pragma solidity ^0.5.17;


contract Migrations {
  address public owner;
  uint public last_completed_migration;

  constructor() public {
    owner = msg.sender;
  }

  modifier restricted() {
    if (msg.sender == owner) _;
  }

  function setCompleted(uint completed) public restricted {
    last_completed_migration = completed;
  }

  function upgrade(address new_address) public restricted {
    Migrations upgraded = Migrations(new_address);
    upgraded.setCompleted(last_completed_migration);
  }
}

// File: Ownable.sol



pragma solidity ^0.5.17;


/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    constructor () internal {
        _owner = msg.sender;
        emit OwnershipTransferred(address(0), _owner);
    }

    /**
     * @return the address of the owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == msg.sender, "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Allows the current owner to relinquish control of the contract.
     * It will not be possible to call the functions with the `onlyOwner`
     * modifier anymore.
     * @notice Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

// File: Proxy.sol



pragma solidity ^0.5.17;

import "./Implementation.sol";
import "./Ownable.sol";


contract Proxy is Implementation, Ownable {

    constructor(address _implementation) public Ownable() {
        _setImplementation(_implementation);
    }

    /**
     * @dev Fallback function allowing to perform a delegatecall
     * to the given implementation. This function will return
     * whatever the implementation call returns
     */
    function ()
        external
        payable
    {
        address impl = implementation;
        require(impl != address(0), "Implementation address is invalid");
        assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize)
            let result := delegatecall(gas, impl, ptr, calldatasize, 0, 0)
            let size := returndatasize
            returndatacopy(ptr, 0, size)

            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
        }
    }

    /**
     * @dev Upgrades the implementation address
     * @param _newImplementation address of the new implementation
     */
    function upgradeTo(address _newImplementation)
        external onlyOwner
    {
        require(
            implementation != _newImplementation,
            "New implementation address already set"
        );
        isSetup = false;
        _setImplementation(_newImplementation);
    }

    /**
     * @dev Sets the address of the current implementation
     * @param _newImp address of the new implementation
     */
    function _setImplementation(address _newImp) internal {
        implementation = _newImp;
    }
}

// File: SafeMath.sol



pragma solidity ^0.5.17;


/**
 * @title SafeMath
 * @dev Unsigned math operations with safety checks that revert on error.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}