contract HumanToken is SafeMath {
    string public constant name                         = "Human Protocol Finance";         // Name of the token
    string public constant symbol                       = "HUMAN";                          // Symbol of token
    uint256 public constant decimals                    = 18;                               // Decimal of token
    uint256 public _totalsupply                         = 100000 * 10 ** decimals;          // Total supply
    uint256 public _circulatingSupply                   = 65000 * 10 ** decimals;           // Circulating supply
    uint256 public _mintingTokens                       = 50000 * 10 ** decimals;           // Minting tokens
    uint256 public _founderTokens                       = 20000 * 10 ** decimals;           // Founder tokens
    uint256 public _privateSeedTokens                   = 15000 * 10 ** decimals;           // Private seed tokens
    uint256 public _mintingTokensUnlocked               = 0;
    uint256 public _founderTokensUnlocked               = 0;
    uint256 public _privateSeedTokensUnlocked           = 0;
    uint256 public _lastMintingUnlock                   = 0;
    uint256 public _lastFounderUnlock                   = 0;
    uint256 public _lastPrivateUnlock                   = 0;
    address public owner                                = msg.sender;                       // Owner of smart contract
    address public admin                                = msg.sender;   
    address public mintingAdmin                         = 0x6FdBD9a7037e82aCd075E0Ff071d6Eab73870caa;   
    address public founderAdmin                         = 0xB84463700487608A3E7d1FAD3F098C0f3A149308;   
    address public privateAdmin                         = 0xf95d91Ab28548038F6cd5391c32E3E166E4D335F;    
    uint256 public _contractTime                        = now; 
    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint)) private _allowances;
    
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval (address indexed IFVOwner, address indexed spender, uint value);
    
    // Only owner can access the function
    modifier onlyOwner() {
        if (msg.sender != owner) {
            revert();
        }
        _;
    }
    
    // Only admin can access the function
    modifier onlyAdmin() {
        if (msg.sender != admin) {
            revert();
        }
        _;
    }
    
    constructor() public {
        balances[msg.sender]        = _circulatingSupply;
        emit Transfer(0, msg.sender, _circulatingSupply);
    }
    
    // Show token balance of address owner
    function balanceOf(address _owner) public view returns (uint256 balance) {
        return balances[_owner];
    }
    
    // Token transfer function
    // Token amount should be in 18 decimals (eg. 199 * 10 ** 18)
    function transfer(address _to, uint256 _amount ) public {
        require(balances[msg.sender] >= _amount && _amount >= 0);
        balances[msg.sender]            = sub(balances[msg.sender], _amount);
        balances[_to]                   = add(balances[_to], _amount);
        emit Transfer(msg.sender, _to, _amount);
    }
    
    // Burn Tokens
    function burntokens(uint256 _amount) external onlyOwner {
        require(balances[msg.sender] >= _amount && _amount >= 0);
        _totalsupply                    = sub(_totalsupply, _amount);
        balances[msg.sender]            = sub(balances[msg.sender], _amount);
    }
    
    // Minting Tokens
    function unlockMintingTokens(uint256 _amount) external onlyAdmin {
        require(_mintingTokensUnlocked <= _mintingTokens);
        _mintingTokensUnlocked          = add(_mintingTokensUnlocked, _amount);
        _totalsupply                    = add(_totalsupply, _amount);
        balances[mintingAdmin]          = add(balances[mintingAdmin], _amount);
        _lastMintingUnlock              = now;
        emit Transfer(0, mintingAdmin, _amount);
    }
    
    // Founder Tokens
    function unlockFounderTokens(uint256 _amount) external onlyAdmin {
        require(now > (_contractTime+180 days)); // After 6months
        require(_amount <= 2000*10**18);
        require(now > (_lastFounderUnlock+30 days)); // Once in a month
        require(_founderTokensUnlocked <= _founderTokens);
        _founderTokensUnlocked          = add(_founderTokensUnlocked, _amount);
        balances[founderAdmin]          = add(balances[founderAdmin], _amount);
        _lastFounderUnlock              = now;
        emit Transfer(0, founderAdmin, _amount);
    }
    
    // Private Seed Tokens
    function unlockPrivateSeedTokens() external onlyAdmin {
        uint256 unlockPrivateAmount     = 5000*10**18;
        require(now > (_lastPrivateUnlock+30 days)); // Once in a month
        require(_privateSeedTokensUnlocked <= _privateSeedTokens);
        _privateSeedTokensUnlocked      = add(_privateSeedTokensUnlocked, unlockPrivateAmount);
        balances[privateAdmin]          = add(balances[privateAdmin], unlockPrivateAmount);
        _lastPrivateUnlock              = now;
        emit Transfer(0, privateAdmin, unlockPrivateAmount);
    }
    
    function allowance(address _owner, address spender) public view returns (uint) {
        return _allowances[_owner][spender];
    }
    
    function approve(address spender, uint amount) public returns (bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }
    
    function transferFrom(address sender, address recipient, uint amount) public returns (bool) {
        require(balances[sender] >= amount && amount >= 0);
        balances[sender]            = sub(balances[sender], amount);
        balances[recipient]                   = add(balances[recipient], amount);
        emit Transfer(sender, recipient, amount);
        _approve(sender, msg.sender, sub(_allowances[sender][msg.sender], amount));
        return true;
    }
    
    function increaseAllowance(address spender, uint addedValue) public returns (bool) {
        _approve(msg.sender, spender, add(_allowances[msg.sender][spender],addedValue));
        return true;
    }
    
    function decreaseAllowance(address spender, uint subtractedValue) public returns (bool) {
        _approve(msg.sender, spender, sub(_allowances[msg.sender][spender],subtractedValue));
        return true;
    }
    
    function _approve(address _owner, address spender, uint 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);
    }
    
    // Total Supply of HumanToken
    function totalSupply() public view returns (uint256 total_Supply) {
        total_Supply = _totalsupply;
    }
    
    // Change Admin of this contract
    function changeAdmin(address _newAdminAddress) external onlyOwner {
        admin = _newAdminAddress;
    }
    
}
function unlockPrivateSeedTokens() external onlyAdmin {
    uint256 unlockPrivateAmount     = 5000*10**18;
    require(now > (_lastPrivateUnlock+30 days)); // Once in a month
    require(_privateSeedTokensUnlocked <= _privateSeedTokens);
    _privateSeedTokensUnlocked      = add(_privateSeedTokensUnlocked, unlockPrivateAmount);
    balances[privateAdmin]          = add(balances[privateAdmin], unlockPrivateAmount);
    _lastPrivateUnlock              = now;
    emit Transfer(0, privateAdmin, unlockPrivateAmount);
}

// Private Seed Tokens