contract TELEToken is ERC20Interface, Owned, SafeMath, Context {
	using Address for address;

	string public symbol;
	string public name;
	uint8 public decimals;
	uint256 private _totalSupply;
	address private _minter;

	mapping(address => uint256) balances;
	mapping(address => mapping(address => uint256)) allowed;

	/// @notice The timestamp after which minting may occur
	uint256 public mintingAllowedAfter;

	/// @notice Minimum time between mints
	uint32 public constant minimumTimeBetweenMints = 1 days * 7;

	/// @notice Cap on the percentage of totalSupply that can be minted at each mint
	/// We are going to divide this by 1000. so below is 0.2 percent of totalSupply
	uint8 public constant mintCap = 2;

	/// @notice A record of each accounts delegate
	mapping(address => address) internal _delegates;

	/// @notice A checkpoint for marking number of votes from a given block
	struct Checkpoint {
		uint32 fromBlock;
		uint256 votes;
	}

	/// @notice A record of votes checkpoints for each account, by index
	mapping(address => mapping(uint32 => Checkpoint)) public checkpoints;

	/// @notice The number of checkpoints for each account
	mapping(address => uint32) public numCheckpoints;

	/// @notice The EIP-712 typehash for the contract's domain
	bytes32 public constant DOMAIN_TYPEHASH =
		keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");

	/// @notice The EIP-712 typehash for the delegation struct used by the contract
	bytes32 public constant DELEGATION_TYPEHASH =
		keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

	/// @notice The EIP-712 typehash for the permit struct used by the contract
	bytes32 public constant PERMIT_TYPEHASH =
		keccak256(
			"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
		);

	/// @notice A record of states for signing / validating signatures
	mapping(address => uint256) public nonces;

	// @notice An event thats emitted when multiple transactions made
	event TransferMultiple(address indexed from, address[] indexed to, uint256[] tokens);

	/// @notice An event thats emitted when an account changes its delegate
	event DelegateChanged(
		address indexed delegator,
		address indexed fromDelegate,
		address indexed toDelegate
	);

	/// @notice An event thats emitted when a delegate account's vote balance changes
	event DelegateVotesChanged(
		address indexed delegate,
		uint256 previousBalance,
		uint256 newBalance
	);

	// @notice An event thats emitted when the minter address is changed
	event MinterChanged(address minter, address newMinter);

	// ------------------------------------------------------------------------
	// Constructor
	///**
     //* @notice Construct a new TELE token
     //* @param account The initial account to grant all the tokens
     //* @param minter_ The account with minting ability
     //* @param mintingAllowedAfter_ The timestamp after which minting may occur
     //*
	// ------------------------------------------------------------------------
	constructor() {
		symbol = "TELE";
		name = "Telefy";
		decimals = 18;
		_totalSupply = 600_000_000e18;
		balances[owner] = _totalSupply;
		emit Transfer(address(0), owner, _totalSupply);
		_minter = 0xa270dA3c3175ED9992c9Ad3B6Bb679Bf81c35BA8;
		mintingAllowedAfter = safeAdd(block.timestamp, minimumTimeBetweenMints);
	}

	// ------------------------------------------------------------------------
	// Total supply
	// ------------------------------------------------------------------------
	function totalSupply() public view override returns (uint256) {
		return safeSub(_totalSupply, balances[address(0)]);
	}

	// ------------------------------------------------------------------------
	// Get the token balance for account tokenOwner
	// ------------------------------------------------------------------------
	function balanceOf(address tokenOwner) public view override returns (uint256 balance) {
		return balances[tokenOwner];
	}

	// ------------------------------------------------------------------------
	// Transfer the balance from token owner's account to to account
	// - Owner's account must have sufficient balance to transfer
	// - 0 value transfers are allowed
	// ------------------------------------------------------------------------
	function transfer(address to, uint256 tokens) external override returns (bool success) {
		require(to != address(0), "TELE: transfer to the zero address");
		_transferTokens(to, tokens);
		emit Transfer(_msgSender(), to, tokens);
		return true;
	}

	// ------------------------------------------------------------------------
	// Transfer the balance from token owner's account to to multiple accounts
	// - Owner's account must have sufficient balance to transfer
	// - 0 value transfers are allowed
	// ------------------------------------------------------------------------
	function transferMultiple(address[] memory to, uint256[] memory tokens)
		external
		returns (bool success)
	{
		require(
			to.length == tokens.length,
			"TELE: number of receiver addresses and number of amounts should be equal"
		);
		for (uint256 i = 0; i < to.length; i++) {
			if (to[i] != address(0)) {
				_transferTokens(to[i], tokens[i]);
			}
		}
		emit TransferMultiple(_msgSender(), to, tokens);
		return true;
	}

	// ------------------------------------------------------------------------
	// Token owner can approve for spender to transferFrom(...) tokens
	// from the token owner's account
	//
	// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
	// recommends that there are no checks for the approval double-spend attack
	// as this should be implemented in user interfaces
	// ------------------------------------------------------------------------
	function approve(address spender, uint256 tokens) public override returns (bool success) {
		require(spender != address(0), "TELE: transfer to the zero address");
		allowed[_msgSender()][spender] = tokens;
		emit Approval(_msgSender(), spender, tokens);
		return true;
	}

	// ------------------------------------------------------------------------
	// @notice Triggers an approval from owner to spends
	// @param owner The address to approve from
	// @param spender The address to be approved
	// @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
	// @param deadline The time at which to expire the signature
	// @param v The recovery byte of the signature
	// @param r Half of the ECDSA signature pair
	// @param s Half of the ECDSA signature pair
	// ------------------------------------------------------------------------
	function permit(
		address owner,
		address spender,
		uint256 rawAmount,
		uint256 deadline,
		uint8 v,
		bytes32 r,
		bytes32 s
	) external {
		bytes32 domainSeparator = keccak256(
			abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))
		);
		bytes32 structHash = keccak256(
			abi.encode(PERMIT_TYPEHASH, owner, spender, rawAmount, nonces[owner]++, deadline)
		);
		bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
		address signatory = ecrecover(digest, v, r, s);
		require(signatory != address(0), "TELE::permit: invalid signature");
		require(signatory == owner, "TELE::permit: unauthorized");
		require(block.timestamp <= deadline, "TELE::permit: signature expired");

		allowed[owner][spender] = rawAmount;

		emit Approval(owner, spender, rawAmount);
	}

	// ------------------------------------------------------------------------
	// Transfer tokens from the from account to the to account
	//
	// The calling account must already have sufficient tokens approve(...)-d
	// for spending from the from account and
	// - From account must have sufficient balance to transfer
	// - Spender must have sufficient allowance to transfer
	// - 0 value transfers are allowed
	// ------------------------------------------------------------------------
	function transferFrom(
		address from,
		address to,
		uint256 tokens
	) external override returns (bool success) {
		balances[from] = safeSub(balances[from], tokens);
		allowed[from][_msgSender()] = safeSub(allowed[from][_msgSender()], tokens);
		emit Approval(from, to, tokens);
		balances[to] = safeAdd(balances[to], tokens);
		emit Transfer(from, to, tokens);
		_moveDelegates(_delegates[from], _delegates[to], tokens);
		return true;
	}

	// ------------------------------------------------------------------------
	// Returns the amount of tokens approved by the owner that can be
	// transferred to the spender's account
	// ------------------------------------------------------------------------
	function allowance(address tokenOwner, address spender)
		public
		view
		override
		returns (uint256 remaining)
	{
		return allowed[tokenOwner][spender];
	}

	// ------------------------------------------------------------------------
	// @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.
	// ------------------------------------------------------------------------
	function increaseAllowance(address spender, uint256 addedValue)
		external
		virtual
		returns (bool)
	{
		approve(spender, safeAdd(allowed[_msgSender()][spender], 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.
	// ------------------------------------------------------------------------
	function decreaseAllowance(address spender, uint256 subtractedValue)
		external
		virtual
		returns (bool)
	{
		approve(spender, safeSub(allowed[_msgSender()][spender], subtractedValue));
		return true;
	}

	// ------------------------------------------------------------------------
	// Token owner can approve for spender to transferFrom(...) tokens
	// from the token owner's account. The spender contract function
	// receiveApproval(...) is then executed
	// ------------------------------------------------------------------------
	function approveAndCall(
		address spender,
		uint256 tokens,
		bytes memory data
	) external returns (bool success) {
		allowed[_msgSender()][spender] = tokens;
		emit Approval(_msgSender(), spender, tokens);
		ApproveAndCallFallBack(spender).receiveApproval(_msgSender(), tokens, address(this), data);
		return true;
	}

	// ------------------------------------------------------------------------
	// Owner can transfer out any accidentally sent ERC20 tokens
	// ------------------------------------------------------------------------
	function transferAnyERC20Token(address tokenAddress, uint256 tokens)
		external
		onlyOwner
		returns (bool success)
	{
		return ERC20Interface(tokenAddress).transfer(owner, tokens);
	}

	// ------------------------------------------------------------------------
	// @dev Destroys `amount` tokens from `account`'s allowance, reducing the
	// total supply which requires approval from user before this action can be performed.
	// Emits a {Transfer} event with `to` set to the zero address.
	// ------------------------------------------------------------------------
	function burn(address account, uint256 amount) external {
		require(_msgSender() == _minter, "TELE::burn: only the minter can mint");
		require(account != address(0), "TELE: burn from the zero address");

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

		balances[account] = safeSub(balances[account], amount);

		// Sets `amount` as the allowance of `spender`
		allowed[account][_msgSender()] = safeSub(allowed[account][_msgSender()], amount);
		emit Approval(account, _msgSender(), amount);

		_totalSupply = safeSub(_totalSupply, amount);
		emit Transfer(account, address(0), amount);
		_moveDelegates(address(0), _delegates[account], 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.
	// ------------------------------------------------------------------------
	function mint(address account, uint256 amount) external {
		require(_msgSender() == _minter, "TELE::mint: only the minter can mint");
		require(block.timestamp >= mintingAllowedAfter, "TELE::mint: minting not allowed yet");
		require(account != address(0), "TELE: mint to the zero address");

		// record the mint
		mintingAllowedAfter = safeAdd(block.timestamp, minimumTimeBetweenMints);

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

		// mint amount should not exceed mint cap
		require(amount <= safeDiv(safeMul(_totalSupply, mintCap), 1000));
		_totalSupply = safeAdd(_totalSupply, amount);
		balances[account] = safeAdd(balances[account], amount);
		emit Transfer(address(0), account, amount);
		_moveDelegates(address(0), _delegates[account], amount);
	}

	// ------------------------------------------------------------------------
	// @notice Change the minter address
	// @param minter_ The address of the new minter
	// ------------------------------------------------------------------------
	function setMinter(address minter_) external {
		require(
			_msgSender() == _minter,
			"TELE::setMinter: only the minter can change the minter address"
		);
		emit MinterChanged(_minter, minter_);
		_minter = minter_;
	}

	// ------------------------------------------------------------------------
	// @notice Delegate votes from `msg.sender` to `delegatee`
	// @param delegator The address to get delegatee for
	// ------------------------------------------------------------------------
	function delegates(address delegator) external view returns (address) {
		return _delegates[delegator];
	}

	// ------------------------------------------------------------------------
	// @notice Delegate votes from `msg.sender` to `delegatee`
	// @param delegatee The address to delegate votes to
	// ------------------------------------------------------------------------
	function delegate(address delegatee) external {
		return _delegate(_msgSender(), delegatee);
	}

	// ------------------------------------------------------------------------
	// @notice Delegates votes from signatory to `delegatee`
	// @param delegatee The address to delegate votes to
	// @param nonce The contract state required to match the signature
	// @param expiry The time at which to expire the signature
	// @param v The recovery byte of the signature
	// @param r Half of the ECDSA signature pair
	// @param s Half of the ECDSA signature pair
	// ------------------------------------------------------------------------
	function delegateBySig(
		address delegatee,
		uint256 nonce,
		uint256 expiry,
		uint8 v,
		bytes32 r,
		bytes32 s
	) external {
		bytes32 domainSeparator = keccak256(
			abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))
		);

		bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));

		bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));

		address signatory = ecrecover(digest, v, r, s);
		require(signatory != address(0), "TELE::delegateBySig: invalid signature");
		require(nonce == nonces[signatory]++, "TELE::delegateBySig: invalid nonce");
		require(block.timestamp <= expiry, "TELE::delegateBySig: signature expired");
		return _delegate(signatory, delegatee);
	}

	// ------------------------------------------------------------------------
	// @notice Gets the current votes balance for `account`
	// @param account The address to get votes balance
	// @return The number of current votes for `account`
	// ------------------------------------------------------------------------
	function getCurrentVotes(address account) external view returns (uint256) {
		uint32 nCheckpoints = numCheckpoints[account];
		return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
	}

	// ------------------------------------------------------------------------
	// @notice Determine the prior number of votes for an account as of a block number
	// @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
	// @param account The address of the account to check
	// @param blockNumber The block number to get the vote balance at
	// @return The number of votes the account had as of the given block
	// ------------------------------------------------------------------------
	function getPriorVotes(address account, uint256 blockNumber) external view returns (uint256) {
		require(blockNumber < block.number, "TELE::getPriorVotes: not yet determined");

		uint32 nCheckpoints = numCheckpoints[account];
		if (nCheckpoints == 0) {
			return 0;
		}

		// First check most recent balance
		if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
			return checkpoints[account][nCheckpoints - 1].votes;
		}

		// Next check implicit zero balance
		if (checkpoints[account][0].fromBlock > blockNumber) {
			return 0;
		}

		uint32 lower = 0;
		uint32 upper = nCheckpoints - 1;
		while (upper > lower) {
			uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
			Checkpoint memory cp = checkpoints[account][center];
			if (cp.fromBlock == blockNumber) {
				return cp.votes;
			} else if (cp.fromBlock < blockNumber) {
				lower = center;
			} else {
				upper = center - 1;
			}
		}
		return checkpoints[account][lower].votes;
	}

	function _transferTokens(address to, uint256 tokens) internal {
		balances[_msgSender()] = safeSub(balances[_msgSender()], tokens);
		balances[to] = safeAdd(balances[to], tokens);
		_moveDelegates(_delegates[_msgSender()], _delegates[to], tokens);
	}

	function _delegate(address delegator, address delegatee) internal {
		address currentDelegate = _delegates[delegator];
		uint256 delegatorBalance = balanceOf(delegator); // balance of underlying TELEs (not scaled);
		_delegates[delegator] = delegatee;

		emit DelegateChanged(delegator, currentDelegate, delegatee);

		_moveDelegates(currentDelegate, delegatee, delegatorBalance);
	}

	function _moveDelegates(
		address srcRep,
		address dstRep,
		uint256 amount
	) internal {
		if (srcRep != dstRep && amount > 0) {
			if (srcRep != address(0)) {
				// decrease old representative
				uint32 srcRepNum = numCheckpoints[srcRep];
				uint256 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
				uint256 srcRepNew = safeSub(srcRepOld, amount);
				_writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
			}

			if (dstRep != address(0)) {
				// increase new representative
				uint32 dstRepNum = numCheckpoints[dstRep];
				uint256 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
				uint256 dstRepNew = safeAdd(dstRepOld, amount);
				_writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
			}
		}
	}

	function _writeCheckpoint(
		address delegatee,
		uint32 nCheckpoints,
		uint256 oldVotes,
		uint256 newVotes
	) internal {
		uint32 blockNumber = safe32(
			block.number,
			"TELE::_writeCheckpoint: block number exceeds 32 bits"
		);

		if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
			checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
		} else {
			checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
			numCheckpoints[delegatee] = nCheckpoints + 1;
		}

		emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
	}

	function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {
		require(n < 2**32, errorMessage);
		return uint32(n);
	}

	function getChainId() internal view returns (uint256) {
		uint256 chainId;
		assembly {
			chainId := chainid()
		}
		return chainId;
	}

	function _beforeTokenTransfer(
		address from,
		address to,
		uint256 amount
	) internal virtual {}
}
// ----------------------------------------------------------------------------
// TELE Token, with the addition of symbol, name and decimals and assisted
// token transfers
// TELE is Governance token for TELEFY
// ----------------------------------------------------------------------------
function transferMultiple(address[] memory to, uint256[] memory tokens)
	external
	returns (bool success)
{
	require(
		to.length == tokens.length,
		"TELE: number of receiver addresses and number of amounts should be equal"
	);
	for (uint256 i = 0; i < to.length; i++) {
		if (to[i] != address(0)) {
			_transferTokens(to[i], tokens[i]);
		}
	}
	emit TransferMultiple(_msgSender(), to, tokens);
	return true;
}

// ------------------------------------------------------------------------
// Transfer the balance from token owner's account to to multiple accounts
// - Owner's account must have sufficient balance to transfer
// - 0 value transfers are allowed
// ------------------------------------------------------------------------