// File: Canary.sol



// SPDX-License-Identifier: MIT

/*
Because sometimes 'Production' is just another phrase for 'Our Largest Beta Test!' - Canary

Welcome to Canary - where a splash of humor meets a surge of innovation! 
Designed with a twinkle in our eyes and a robust roadmap in our hands, Canary is not your everyday meme Coin. 
It's a hilariously serious, technology-driven mechanism to pre-test our next big product. 
Canary Coin embodies our philosophy that there's nothing quite as thrilling - or informative - as testing in live production.

Backed by a myriad of robust features, our Coin doesn't just chirp; it sings tunes of progress, foresight, and unorthodox strategy. 
After all, if you're going to fail, why not fail fast, iterate faster, and have a hearty laugh along the way? 
The biggest production stage in the world is waiting for us - let's embrace the chaos with Canary!

Telegram: https://t.me/CanaryCoin

Features:
- Launch protection
- Base Buy/Sell tax: 5%
- MaxTx: 1%
- MaxWallet: 2%
- Trade tax: 0% (Between wallets)
- Enable/Disable Base tax (For marketing and promotions)
- RenounceOwnership

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@@@@@@@@@@@@@
@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@@@@@@@@@@
@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@@@@@@@
@@@@@@@,,,,,,,,,,,,,,,,@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,,,@@@@@@
@@@@@,,,,,,,,,,,,,,@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,@@@@
@@@@,,,,,,,,,,,,@@@@@@@@@@@@,,,@@@@@#,,,,,,,,,,,,,,,,,,,,,,,,@@@
@@@,,,,,,,,,,,@@@@@@@@@@@@@@,,,@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,@@
@@,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,@
@,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@/,,,,,,,,,,,,,,,,,,,,,,,,,,
@,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,
@,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,
@,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,
@,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,@
@@,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,@
@@@,,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,@@
@@@@#,,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@,,,,@@@@
@@@@@@,,,,,,,,,,,,,,(@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@,,,,,,,,,,,,,,,,,(@@@@@@@@@@@@@,,,,,,@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@,,,,,,,,,,,,,,,,,,@@@@@@@@@@@@@@@@@@@@@@@
*/

pragma solidity 0.8.19;

//CAUTION
//This version of SafeMath should only be used with Solidity 0.8 or later,
//because it relies on the compiler's built in overflow checks.
//https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol
library SafeMath {
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

//https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Context.sol
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }
    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

//https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol
abstract contract Ownable is Context {
    address private _owner;
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    constructor() {
        _transferOwnership(_msgSender());
    }
    modifier onlyOwner() {
        _checkOwner();
        _;
    }
    function owner() public view virtual returns (address) {
        return _owner;
    }
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

//https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount)external returns (bool);
    function allowance(address owner, address spender)external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender,address recipient,uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner,address indexed spender,uint256 value);
}

//https://github.com/Uniswap/v2-core/blob/master/contracts/interfaces/IUniswapV2Factory.sol
interface IUniswapV2Factory {
    function createPair(address tokenA, address tokenB) external returns (address pair);
}

//https://github.com/Uniswap/v2-periphery/blob/master/contracts/interfaces/IUniswapV2Router02.sol
interface IUniswapV2Router02 {
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function factory() external pure returns (address);
    function WETH() external pure returns (address);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
}

contract CanaryCoin is IERC20, Ownable {
    
    using SafeMath for uint256;
    string private _name = "Canary";
    string private _symbol = "CNY";
    uint8 private _decimals = 18;
    
    mapping(address => uint256) internal _balances;
    mapping(address => mapping(address => uint256)) internal _allowances;
    
    uint256 internal _totalSupply = 1000000000*10**18; 
    uint256 public _maxTxAmount = 10000000*10**18; //1%
    uint256 public _maxWalletSize = 20000000*10**18; //2%
    
    mapping(address => bool) private isExcludedFromTax;
    
    uint256 public _buyTax = 500; //  5%
    uint256 public _sellTax = 500; // 5%
    address public taxWallet = 0xa0e230B8E6A2E0b8a0D4C57a78C3D7e9D7dAA2e3;  //Tax wallet
    uint256 public tradingStartTime;
    address private uniswapV2Pair;
    bool private tradingOpen;
    IUniswapV2Router02 private uniswapV2Router;
    bool private swapEnabled = false;
    bool private taxEnabled = true;
    uint256 public _inbetweenTax_ = 0; // 0%
    uint256 public _buyTaxTotal;
    uint256 public _sellTaxTotal;
    uint256 public _inbetweenTaxTotal;    
    
    constructor() {
        isExcludedFromTax[msg.sender] = true;
        isExcludedFromTax[address(this)] = true;
        isExcludedFromTax[taxWallet] = true; //Add multiple times with different wallets that need to be excluded.
        _balances[msg.sender] = _totalSupply;           
        emit Transfer(address(0), msg.sender, _totalSupply);
    }

    function name() public view returns (string memory) {
        return _name;
    }
    function symbol() public view returns (string memory) {
        return _symbol;
    }
    function decimals() public view returns (uint8) {
        return _decimals;
    }
    function totalSupply() public override view returns (uint256) {
        return _totalSupply;
    }
    function balanceOf(address account) public override view returns (uint256) {
         return _balances[account];
    }
    function transfer(address recipient, uint256 amount) public override virtual returns (bool) {
       _transfer(msg.sender,recipient,amount);
        return true;
    }
    function allowance(address owner, address spender) public override view returns (uint256) {
        return _allowances[owner][spender];
    }
    function approve(address spender, uint256 amount) public override returns (bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }
    function transferFrom(address sender, address recipient, uint256 amount) public override virtual returns (bool) {
        _transfer(sender,recipient,amount);       
        _approve(sender,msg.sender,_allowances[sender][msg.sender].sub( amount,"ERC20: transfer amount exceeds allowance"));
        return true;
    }
    function _approve(address owner, address spender, uint256 amount) private {
        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);
    }

    //Transfer transactions
    function _transfer(address sender, address recipient, uint256 amount) private {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");
        require(amount <= _maxTxAmount, "Exceeds the maxTxAmount.");
        require(balanceOf(recipient) + amount <= _maxWalletSize, "Exceeds the maxWalletSize.");
        uint256 transferAmount = amount;
     if(taxEnabled){
         updateTaxRate();
            if(isExcludedFromTax[sender] && isExcludedFromTax[recipient]){
                transferAmount = amount;
            }
            if(!isExcludedFromTax[sender] && !isExcludedFromTax[recipient]){
                transferAmount = betweenTax(sender,amount);
            }
            if(isExcludedFromTax[sender] && !isExcludedFromTax[recipient]){
                transferAmount = BuyTax(sender,amount);
            }
            if(!isExcludedFromTax[sender] && isExcludedFromTax[recipient]){
                transferAmount = SellTax(sender,amount);       
            }   
        }
        _balances[sender] = _balances[sender].sub(amount);
        _balances[recipient] = _balances[recipient].add(transferAmount);    
        emit Transfer(sender, recipient, transferAmount);
    }
    
    //Buy tax on transactions
    function BuyTax(address account, uint256 amount) private returns (uint256) {
        uint256 transferAmount = amount;
        uint256 buyTax = amount.mul(_buyTax).div(10000); //amount * 500 / 10000 = 5% base tax 
        if(buyTax > 0){
            transferAmount = transferAmount.sub(buyTax);
            _balances[address(taxWallet)] = _balances[address(taxWallet)].add(buyTax);
            _buyTaxTotal = _buyTaxTotal.add(buyTax);
            emit Transfer(account,address(taxWallet),buyTax);
        }  
        return transferAmount;
    }

    //Sell tax on transactions
    function SellTax(address account, uint256 amount) private  returns (uint256) {      
        uint256 transferAmount = amount;
        uint256 sellTax = amount.mul(_sellTax).div(10000);  //amount * 500 / 10000 = 5% base tax 
        if (sellTax > 0){
            transferAmount = transferAmount.sub(sellTax);
            _balances[address(taxWallet)] = _balances[address(taxWallet)].add(sellTax);
            _sellTaxTotal = _sellTaxTotal.add(sellTax);
            emit Transfer(account,address(taxWallet),sellTax);
        }
        return transferAmount;
    }

    //Tax on transactions between traders/ wallets
    function betweenTax(address account, uint256 amount) private  returns (uint256) {
        uint256 transferAmount = amount;
        uint256 _inbetweenTax = amount.mul(_inbetweenTax_).div(10000); // amount * 0 / 10000 = 0% base tax 
        if (_inbetweenTax > 0){
            transferAmount = transferAmount.sub(_inbetweenTax);
            _balances[address(taxWallet)] = _balances[address(taxWallet)].add(_inbetweenTax);
            _inbetweenTaxTotal = _inbetweenTaxTotal.add(_inbetweenTax);
            emit Transfer(account,address(taxWallet),_inbetweenTax);
        }
        return transferAmount;
    }

    /*
       Launch Taxes: 
       - First 10 minutes tax is 45%
       - After 10 minutes tax is 25%
       - After 20 minutes tax is 5% = Base tax
    */
     function updateTaxRate() internal {
        if (block.timestamp <= tradingStartTime + 10 minutes ) { // 1st 10 minutes tax will be 45%
            if (_buyTax != 4500) { //45%
                _buyTax = 4500;
            }
            if (_sellTax != 4500) {
                _sellTax = 4500;
            }
        }
        else if (block.timestamp  >= tradingStartTime + 10 minutes && block.timestamp  <= tradingStartTime + 20 minutes  ) { // after 10 minutes tax will be 25%
             if (_buyTax != 2500) {//25%
                _buyTax = 2500;
            }
            if (_sellTax != 2500) {
                _sellTax = 2500;
            }
        }
        else if (block.timestamp  >= tradingStartTime + 20 minutes) { // after 20 minutes tax will be 5% = base tax
              if (_buyTax != 500) {//5%
                _buyTax = 500;
            }
            if (_sellTax != 500) {
                _sellTax = 500;
            }
        }
    }
    
    //Will open the trading, create pair and fill LP
    function openTrading() external onlyOwner() {
        require(!tradingOpen,"trading is already open");
        uniswapV2Router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
        _approve(address(this), address(uniswapV2Router), _totalSupply);
        uniswapV2Pair = IUniswapV2Factory(uniswapV2Router.factory()).createPair(address(this), uniswapV2Router.WETH());
        uniswapV2Router.addLiquidityETH{value: address(this).balance}(address(this),balanceOf(address(this)),0,0,owner(),block.timestamp);
        IERC20(uniswapV2Pair).approve(address(uniswapV2Router), type(uint).max);
        isExcludedFromTax[address(uniswapV2Router)] = true;
        swapEnabled = true;
        tradingOpen = true;
        tradingStartTime = block.timestamp;
    }
    
    //Enables base tax on transactions
    function taxEnable() public onlyOwner {
        taxEnabled = true;
    }
    //Disables base tax on transactions, used for marketing and promotions.
    function taxDisable() public onlyOwner {
        taxEnabled = false;
    }
}