contract IPMToken is ERC20PresetMinterPauser, SocialProofable {
    using SafeMath for uint256;

    //////////////////////////////////////
    // Base Token configuration         //
    //////////////////////////////////////
    
    // token name
    string public constant TOKEN_NAME               =   "TIMERS";
    // token symbol
    string public constant TOKEN_SYMBOL             =   "IPM";
    // real initial supply is 14.6mio. 
    // 9M are reserved for crowdsale and will be minted on demand.
    uint256 public constant TOKEN_INITIAL_SUPPLY        =   5600000  * (10 ** 18); 
    // 14.6M max supply after crowdsale
    uint256 public constant MAXIMUM_CROWDSALE_SUPPLY    =   14600000 * (10 ** 18); 
    // 50M maximum supply
    uint256 public constant SUPPLY_CAP                  =   50000000 * (10 ** 18); 

    // duration for the minting deactivation after crowdsale
    uint256 private constant mintLockTimeframe          =   365 days;
    // date when token becomes mintable again
    uint256 private tokenMintableDate                   =   now + mintLockTimeframe;
    // duration for the cooldown until tokens are transferable
    uint256 private constant tokenActivationTimeframe   =   5 days;
    // unpause date
    uint256 private tokenActivationDate                 =   now + tokenActivationTimeframe; 
     // switch if crowdsale has ended
    bool private crowdSaleFinished                      =   false;

    //////////////////////////////////////
    // Data for social proof            //
    //////////////////////////////////////
    string public constant socialTwitter = "TIMERSnetwork";
    string public constant socialTelegram = "TIMERSipm";
    string public constant socialWebsite = "timers.network";
    string public constant socialGithub = "timersnetwork";
    uint256 public socialTwitterProof;
    bytes public socialGithubProof;
    
    /**
     * @dev Constructor of IPM Token contract. Mints initial supply
     *      and sets access roles + Token Data via inherited class.
     */
    constructor() ERC20PresetMinterPauser(TOKEN_NAME,TOKEN_SYMBOL) public {
        // mint initial supply
        _mint(msg.sender, TOKEN_INITIAL_SUPPLY);

    }

    ///////////////////////////////////////////
    // Overrides                             //
    ///////////////////////////////////////////
    function mint(address to, uint256 amount) public virtual override {
        require(crowdSaleFinished == false || (crowdSaleFinished == true && now > tokenMintableDate), "Error: minting is currently locked");
        if(crowdSaleFinished == false) {
            require(totalSupply().add(amount) <= MAXIMUM_CROWDSALE_SUPPLY, "CrowdSale: cap exceeded");
        }
        super.mint(to,amount);
    }

    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
        super._beforeTokenTransfer(from,to,amount);
        // check if token is active already or sender is admin / minter
        require(tokenActive() || from == address(0), "Error: Token is not active yet");

        // minting
        if (from == address(0)) { 
            // Prevent minting of tokens beyond max supply
            require(totalSupply().add(amount) <= SUPPLY_CAP, "Max cap exceeded");
        }
        
    }

    /**
     * @dev Checks whether the token is already active 
     *      (crowdsale finsihed and cooldown date reached)
     */
    function tokenActive() public view returns(bool) {
        // admin can always send
        if(hasRole(DEFAULT_ADMIN_ROLE,msg.sender)) { return true; }

        if(crowdSaleFinished == true && now > tokenActivationDate) { return true; }

        return false;


    }
    /**
     * @dev Resets/Activates CrowdSale and deactivates token again
     *
     * Requirements:
     *
     * - the caller must have the `DEFAULT_ADMIN_ROLE`.
     */
    function resetCrowdSale() external {
        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Error: You are not allowed to use this command");
        require(crowdSaleFinished == true, "Error: CrowdSale already active");
        crowdSaleFinished   =   false;
    }

    /**
     * @dev Checks whether the token is already active 
     *      (crowdsale finsihed and cooldown date reached)
     *
     * Requirements:
     *
     * - the caller must have the `DEFAULT_ADMIN_ROLE`.
     */
    function finishCrowdSale() external {
        require(hasRole(DEFAULT_ADMIN_ROLE,msg.sender), "Error: You are not allowed to use this command");
        require(crowdSaleFinished == false, "Error: CrowdSale already finished");

        // crowdsale finished
        crowdSaleFinished   =   true;
        // define date when token unlocks and becomes active: now + 5 days
        tokenActivationDate =   now + tokenActivationTimeframe;
        // define date when minting unlocks: now + 365 days
        tokenMintableDate   =   now + mintLockTimeframe;

        emit CrowdSaleFinished(
            totalSupply().sub(TOKEN_INITIAL_SUPPLY),
            tokenMintableDate,
            tokenActivationDate
        );
    }

    function getTokenActivationDate() public view returns(uint256) {
        return tokenActivationDate;
    }

    function getTokenMintableDate() public view returns(uint256) {
        return tokenMintableDate;
    }

    ///////////////////////////////////////////
    // Events                                //
    ///////////////////////////////////////////
    event CrowdSaleFinished(
        uint256 tokenPurchased,
        uint256 mintingLockDate,
        uint256 tokenActivationDate
    );

    ///////////////////////////////////////////
    // Social proof interface implementation //
    ///////////////////////////////////////////
    /**
     * @dev Get Twitter account for social proof
     */
    function getTwitter() override external view returns(string memory) {
        return socialTwitter;
    }

    /**
     * @dev Get Telegram account for social proof
     */
    function getTelegram() override external view returns(string memory) {
        return socialTelegram;
    }

    /**
     * @dev Get GitHub account for social proof
     */
    function getGithub() override external view returns(string memory) {
        return socialGithub;
    }

    /**
     * @dev Get Website for social proof
     */
    function getWebsite() override external view returns(string memory) {
        return socialWebsite;
    }

     /**
     * @dev Set Twitter account proof
     *
     * Requirements:
     *
     * - the caller must have the `ADMIN_ROLE`.
     */
    function setTwitterProof(uint256 _twitterProof) external {
        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Error: twitter proof can only be set by admin");
        socialTwitterProof    =   _twitterProof;
    }

     /**
     * @dev Get Twitter account proof
     */
    function getTwitterProof() override external view returns(uint256) {
        return socialTwitterProof;
    }

     /**
     * @dev Set Github account proof
     *
     * Requirements:
     *
     * - the caller must have the `ADMIN_ROLE`.
     */
    function setGithubProof(bytes calldata _githubProof) external {
        require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Error: github proof can only be set by admin");
        socialGithubProof =   _githubProof;
    }

     /**
     * @dev Get Github account proof
     */
    function getGithubProof() override external view returns(bytes memory) {
        return socialGithubProof;
    }
}
/**
 * @title IPM Token
 * @dev  ERC20 contract of IPM Token for TIMERS Network
 *       Token is mintable but capped and also disables
 *       minting for 1 year after crowdsale ended.
 *       Tokens will be automatically transferable 5 days 
 *       after crowdsale.
 *
 * More at https://timers.network/
 *
 * @author @KTimersnetwork
 */
function finishCrowdSale() external {
    require(hasRole(DEFAULT_ADMIN_ROLE,msg.sender), "Error: You are not allowed to use this command");
    require(crowdSaleFinished == false, "Error: CrowdSale already finished");

    // crowdsale finished
    crowdSaleFinished   =   true;
    // define date when token unlocks and becomes active: now + 5 days
    tokenActivationDate =   now + tokenActivationTimeframe;
    // define date when minting unlocks: now + 365 days
    tokenMintableDate   =   now + mintLockTimeframe;

    emit CrowdSaleFinished(
        totalSupply().sub(TOKEN_INITIAL_SUPPLY),
        tokenMintableDate,
        tokenActivationDate
    );
}

/**
 * @dev Checks whether the token is already active 
 *      (crowdsale finsihed and cooldown date reached)
 *
 * Requirements:
 *
 * - the caller must have the `DEFAULT_ADMIN_ROLE`.
 */