contract Cryotoken is ERC20, Ownable {
  constructor() public ERC20("CRYO", "Cryotoken") { // Symbol and Name
    _balances[_msgSender()] = _totalSupply;
    emit Transfer(address(0), _msgSender(), _totalSupply);
    }
  
  
  event TradingEnabled(bool enabled);
  event TransferFeeChanged(uint256 newFee);
  event FeeRecipientChange(address account);
  event PairAddressSet(address account);
  event AddFeeException(address account);
  event RemoveFeeException(address account);

  bool private activeFee = false;
  bool public tradingEnabled = false;
  uint256 public launchedAt;
  uint256 public transferFee;
  address public feeRecipient;
  address private pairAddress;

  // Exception to transfer fees, for example for Uniswap contracts.
  mapping (address => uint256) private lastBuy;
  mapping (address => bool) public feeException;

  function enableTrading() external onlyOwner() {
    tradingEnabled = true;
    TradingEnabled(true);
    launchedAt = now;
  }

  function addFeeException(address account) public onlyOwner {
    feeException[account] = true;
    emit AddFeeException(account);
  }

  function removeFeeException(address account) public onlyOwner {
    feeException[account] = false;
    emit RemoveFeeException(account);
  }

  function setTransferFee(uint256 fee) public onlyOwner {
    require(fee <= 1400, "Fee cannot be greater than 14%");
    if (fee == 0) {
      activeFee = false;
    } else {
      activeFee = true;
    }
    transferFee = fee;
    emit TransferFeeChanged(fee);
  }

  function setTransferFeeRecipient(address account) public onlyOwner {
    feeRecipient = account;
    emit FeeRecipientChange(account);
  }
  
  function setPairAddress(address account) public onlyOwner {
    pairAddress = account;
    emit PairAddressSet(account);
  }
  
  function _cooldownTimer(address recipient, uint256 amount) internal {    
    if (recipient != pairAddress && recipient != feeRecipient) {
      require(now > launchedAt + 3 minutes  || amount <= 5e19);
      require(now > launchedAt + 3 minutes  || block.timestamp - lastBuy[recipient] > 60);
      lastBuy[recipient] = block.timestamp;
    }
      
  }
  // Transfer recipient recives amount - fee
  function transfer(address recipient, uint256 amount) public override returns (bool) {
    if(_msgSender() != owner() && recipient != owner()) {
        require(tradingEnabled, "Trading is not enabled");
        _cooldownTimer(recipient, amount);
    }
    if (activeFee && feeException[_msgSender()] == false) {
      if (((now - launchedAt)/3600 % 4) == 0) {
        transferFee = 600;
      }
      else if (((now - launchedAt)/3600 % 4) == 1) {
        transferFee = 800;
      }
      else if (((now - launchedAt)/3600 % 4) == 2) {
        transferFee = 1000;
      }
      else if (((now - launchedAt)/3600 % 4) == 3) {
        transferFee = 1200;
      }
      uint256 fee = transferFee.mul(amount).div(10000);
      uint amountLessFee = amount.sub(fee);
      _transfer(_msgSender(), recipient, amountLessFee);
      _transfer(_msgSender(), feeRecipient, fee);
    } else {
      _transfer(_msgSender(), recipient, amount);
    }
    return true;
  }

  // TransferFrom recipient recives amount, sender's account is debited amount + fee
  function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
    if(sender != owner() && recipient != owner()) {
      require(tradingEnabled, "Trading is not enabled");
    }
    if (activeFee && feeException[recipient] == false) {
      if (((now - launchedAt)/3600 % 4) == 0) {
        transferFee = 600;
      }
      else if (((now - launchedAt)/3600 % 4) == 1) {
        transferFee = 800;
      }
      else if (((now - launchedAt)/3600 % 4) == 2) {
        transferFee = 1000;
      }
      else if (((now - launchedAt)/3600 % 4) == 3) {
        transferFee = 1200;
      }
      uint256 fee = transferFee.mul(amount).div(10000);
      uint amountLessFee = amount.sub(fee);
      _transfer(sender, recipient, amountLessFee);
      _transfer(sender, feeRecipient, fee);
    } else {
    _transfer(sender, recipient, amount);
    }
    _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
    return true;
  }

}
function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
  if(sender != owner() && recipient != owner()) {
    require(tradingEnabled, "Trading is not enabled");
  }
  if (activeFee && feeException[recipient] == false) {
    if (((now - launchedAt)/3600 % 4) == 0) {
      transferFee = 600;
    }
    else if (((now - launchedAt)/3600 % 4) == 1) {
      transferFee = 800;
    }
    else if (((now - launchedAt)/3600 % 4) == 2) {
      transferFee = 1000;
    }
    else if (((now - launchedAt)/3600 % 4) == 3) {
      transferFee = 1200;
    }
    uint256 fee = transferFee.mul(amount).div(10000);
    uint amountLessFee = amount.sub(fee);
    _transfer(sender, recipient, amountLessFee);
    _transfer(sender, feeRecipient, fee);
  } else {
  _transfer(sender, recipient, amount);
  }
  _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
  return true;
}

// TransferFrom recipient recives amount, sender's account is debited amount + fee